diff --git a/.classpath b/.classpath index 3f05f311a90b..7bc9cfb36b11 100644 --- a/.classpath +++ b/.classpath @@ -17,5 +17,13 @@ + + + + + + + + diff --git a/.gitignore b/.gitignore index 45a20de82e87..5869e44f19c9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ lib/* *.log *.log.* *.csv +.classpath config.json src/test/data/sandbox/ preferences.json diff --git a/.project b/.project index 1c9339c5f927..ead313116fb9 100644 --- a/.project +++ b/.project @@ -1,7 +1,7 @@ - addressbook-level4 - Project addressbook-level4 created by Buildship. + [Team] main + Project [Team] main created by Buildship. diff --git a/.settings/org.eclipse.ltk.core.refactoring.prefs b/.settings/org.eclipse.ltk.core.refactoring.prefs new file mode 100644 index 000000000000..b196c64a3418 --- /dev/null +++ b/.settings/org.eclipse.ltk.core.refactoring.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/A0122460W.md b/A0122460W.md new file mode 100644 index 000000000000..61a2cfd13dc0 --- /dev/null +++ b/A0122460W.md @@ -0,0 +1,104 @@ +# A0122460W +###### \java\seedu\malitio\logic\commands\CompleteCommand.java +``` java +public class CompleteCommand extends Command{ + + public static final String COMMAND_WORD = "complete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": complete the task or deadline identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d' and a positive integer) " + + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_COMPLETED_TASK = "The floating task is completed in Malitio"; + + public static final String MESSAGE_COMPLETED_DEADLINE = "The deadline is completed in Malitio"; + + public static final String MESSAGE_COMPLETED_TASK_SUCCESS = "Successfully completed floating task."; + + public static final String MESSAGE_COMPLETED_DEADLINE_SUCCESS = "Successfully completed deadline."; + + private final char taskType; + + private final int targetIndex; + + public CompleteCommand(char taskType, int targetIndex) throws IllegalValueException { + assert taskType == 'd' || taskType == 'f'; + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + CommandResult result; + if (taskType=='f') { + result = executeCompleteFloatingTask(); + model.getFuture().clear(); + return result; + } + else { + result = executeCompleteDeadline(); + model.getFuture().clear(); + return result; + } + } + + private CommandResult executeCompleteFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToComplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.completeFloatingTask(taskToComplete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } catch (UniqueFloatingTaskList.FloatingTaskCompletedException e) { + return new CommandResult(MESSAGE_COMPLETED_TASK); + } + return new CommandResult(String.format(MESSAGE_COMPLETED_TASK_SUCCESS, taskToComplete)); + } + + private CommandResult executeCompleteDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToComplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.completeDeadline(deadlineToComplete); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } catch (UniqueDeadlineList.DeadlineCompletedException e) { + return new CommandResult(MESSAGE_COMPLETED_DEADLINE); + } + return new CommandResult(String.format(MESSAGE_COMPLETED_DEADLINE_SUCCESS, deadlineToComplete)); + } + +} +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void completeFloatingTask(ReadOnlyFloatingTask taskToComplete) throws FloatingTaskCompletedException, FloatingTaskNotFoundException { + malitio.completeTask(taskToComplete); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void completeDeadline(ReadOnlyDeadline deadlineToEdit) throws DeadlineCompletedException, DeadlineNotFoundException { + malitio.completeDeadline(deadlineToEdit); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + +``` diff --git a/A0129595N.md b/A0129595N.md new file mode 100644 index 000000000000..54f09ec3af77 --- /dev/null +++ b/A0129595N.md @@ -0,0 +1,1310 @@ +# A0129595N +###### \java\seedu\malitio\logic\commands\AddCommand.java +``` java +/** + * Adds a task to Malitio. + */ +public class AddCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": adds a task to Malitio. Task name cannot contain \'/\'. \n" + + "Parameters: NAME [by DEADLINE] [start STARTTIME end ENDTIME] [t/TAG]...\n" + + "Example: " + COMMAND_WORD + + " Pay John $100 by Oct 11 2359 t/oweMoney"; + + public static final String MESSAGE_SUCCESS = "New task added: %1$s"; + public static final String MESSAGE_DUPLICATE_TASK = "This floating task already exists in Malitio"; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists in Malitio"; + public static final String MESSAGE_DUPLICATE_DEADLINE ="This deadline already exists in Malitio"; + private FloatingTask toAddFloatingTask; + private Deadline toAddDeadline; + private Event toAddEvent; + + /** + * Convenience constructor for floating tasks using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAddFloatingTask = new FloatingTask( + new Name(name), + new UniqueTagList(tagSet) + ); + } + + /** + * Convenience constructor for deadlines using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + + public AddCommand(String name, String date, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAddDeadline = new Deadline( + new Name(name), + new DateTime(date), + new UniqueTagList(tagSet) + ); + } + + /** + * Convenience constructor for events using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, String start, String end, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + // check if start < end + this.toAddEvent = new Event( + new Name(name), + new DateTime(start), + new DateTime(end), + new UniqueTagList(tagSet) + ); + } + + /** + * Executes the command. It will clear the future stack so that no redo can be done. + */ + @Override + public CommandResult execute() { + assert model != null; + if (toAddFloatingTask!=null){ + try { + model.addFloatingTask(toAddFloatingTask); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddFloatingTask)); + } catch (UniqueFloatingTaskList.DuplicateFloatingTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } + } + else if (toAddDeadline != null){ + try { + model.addDeadline(toAddDeadline); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddDeadline)); + } catch (UniqueDeadlineList.DuplicateDeadlineException e) { + return new CommandResult(MESSAGE_DUPLICATE_DEADLINE); + } + } + else { + try { + model.addEvent(toAddEvent); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddEvent)); + } catch (UniqueEventList.DuplicateEventException e) { + return new CommandResult(MESSAGE_DUPLICATE_EVENT); + } + } + } +} +``` +###### \java\seedu\malitio\logic\commands\EditCommand.java +``` java +/** + * Edits a floating task/ deadline/ event identified using it's last displayed index from Malitio. + * Only the attribute(s) that require changes is(are) entered. + */ +public class EditCommand extends Command{ + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ":Edits the task identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d'/'e' and a positive integer) [NAME] [by NEWDATE] [START NEWDATE] [END NEWDATE]\n" + + "Example: " + COMMAND_WORD + " f1 New Name"; + + public static final String MESSAGE_DUPLICATE_TASK = "The intended edit correspond to a pre-existing floating task in Malitio"; + + public static final String MESSAGE_DUPLICATE_DEADLINE = "The intended edit correspond to a pre-existing deadline in Malitio"; + + public static final String MESSAGE_DUPLICATE_EVENT = "The intended edit correspond to a pre-existing event in Malitio"; + + public static final String MESSAGE_INVALID_EVENT = "Event must start before it ends!"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Successfully edited floating task.\nOld: %1$s\nNew: %2$s"; + + public static final String MESSAGE_EDIT_DEADLINE_SUCCESS = "Successfully edited deadline.\nOld: %1$s\nNew: %2$s"; + + public static final String MESSAGE_EDIT_EVENT_SUCCESS = "Successfully edited event.\nOld: %1$s\nNew: %2$s"; + + private final char taskType; + + private final int targetIndex; + + private FloatingTask editedTask; + + private Deadline editedDeadline; + + private Event editedEvent; + + private Name name; + + private DateTime due; + + private DateTime start; + + private DateTime end; + + private UniqueTagList tags; + +``` +###### \java\seedu\malitio\logic\commands\EditCommand.java +``` java + public EditCommand(char taskType, int targetIndex, String name, Set newTags) + throws IllegalValueException { + assert taskType == 'f'; + assert !name.equals("") || !newTags.isEmpty() ; + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + this.tags = processTags(newTags); + } + + public EditCommand(char taskType, int targetIndex, String name, String due, Set newTags) + throws IllegalValueException { + assert taskType == 'd'; + assert !name.equals("") || !due.equals("") || !newTags.isEmpty(); + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + if (!due.equals("")) { + this.due = new DateTime(due); + } + this.tags = processTags(newTags); + } + + public EditCommand(char taskType, int targetIndex, String name, String start, String end, Set newTags) + throws IllegalValueException { + assert taskType == 'e'; + assert !name.equals("") || !start.equals("") || !end.equals("") || !newTags.isEmpty(); + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + if (!start.equals("")) { + this.start = new DateTime(start); + } + if (!end.equals("")) { + this.end = new DateTime(end); + } + this.tags = processTags(newTags); + } + + + /** + * processTags return a UniqueTagList of tags but returns null if no tags were entered. + * @param newTags + * @return UniqueTagList or Null + * @throws IllegalValueException + */ + private UniqueTagList processTags(Set newTags) throws IllegalValueException { + if (!newTags.isEmpty() && newTags.toArray()[0].equals("null") && newTags.size()==1) { + return new UniqueTagList(); + } + else if (!newTags.isEmpty()){ + final Set tagSet = new HashSet<>(); + for (String tagName : newTags) { + tagSet.add(new Tag(tagName)); + } + return new UniqueTagList(tagSet); + } + else { + return null; + } + } + + /** + * fillInTheGaps will replace the task's attributes not entered by the user by extracting from the task to be edited . + * @param ReadOnly + */ + private void fillInTheGaps(ReadOnlyFloatingTask taskToEdit) { + if (this.name==null) { + this.name = taskToEdit.getName(); + } + if (this.tags==null) { + this.tags = taskToEdit.getTags(); + } + } + + private void fillInTheGaps(ReadOnlyDeadline deadlineToEdit) { + if (this.name==null) { + this.name = deadlineToEdit.getName(); + } + if (this.due==null) { + this.due = deadlineToEdit.getDue(); + } + if (this.tags==null) { + this.tags = deadlineToEdit.getTags(); + } + } + + private void fillInTheGaps(ReadOnlyEvent eventToEdit) { + if (this.name==null) { + this.name = eventToEdit.getName(); + } + if (this.start==null) { + this.start = eventToEdit.getStart(); + } + if (this.end==null) { + this.end = eventToEdit.getEnd(); + } + if (this.tags==null) { + this.tags = eventToEdit.getTags(); + } + } + @Override + public CommandResult execute() { + CommandResult result; + if (taskType=='f') { + result = executeEditFloatingTask(); + model.getFuture().clear(); + return result; + } + else if (taskType=='d') { + result = executeEditDeadline(); + model.getFuture().clear(); + return result; + } + else { + result = executeEditEvent(); + model.getFuture().clear(); + return result; + } + + } + + public CommandResult executeEditFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(taskToEdit); + editedTask = new FloatingTask(name,tags); + model.editFloatingTask(editedTask, taskToEdit); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } catch (UniqueFloatingTaskList.DuplicateFloatingTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit, editedTask)); + } + + public CommandResult executeEditDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(deadlineToEdit); + editedDeadline = new Deadline(name,due,tags); + model.editDeadline(editedDeadline, deadlineToEdit); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } catch (UniqueDeadlineList.DuplicateDeadlineException e) { + return new CommandResult(MESSAGE_DUPLICATE_DEADLINE); + } + return new CommandResult(String.format(MESSAGE_EDIT_DEADLINE_SUCCESS, deadlineToEdit, editedDeadline)); + } + + public CommandResult executeEditEvent() { + UnmodifiableObservableList lastShownList = model.getFilteredEventList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_EVENT_DISPLAYED_INDEX); + } + + ReadOnlyEvent eventToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(eventToEdit); + editedEvent = new Event(name, start, end, tags); + model.editEvent(editedEvent, eventToEdit); + } catch (EventNotFoundException pnfe) { + assert false : "The target event cannot be missing"; + } catch (DuplicateEventException e) { + return new CommandResult(MESSAGE_DUPLICATE_EVENT); + } catch (IllegalValueException e) { + return new CommandResult(MESSAGE_INVALID_EVENT); + } + return new CommandResult(String.format(MESSAGE_EDIT_EVENT_SUCCESS, eventToEdit, editedEvent)); + } + +} +``` +###### \java\seedu\malitio\logic\commands\RedoCommand.java +``` java +public class RedoCommand extends Command { + + public static final String COMMAND_WORD = "redo"; + public String result; + + @Override + public CommandResult execute() { + + Stack future = model.getFuture(); + if (future.isEmpty()) { + return new CommandResult("No action to redo!"); + } + InputHistory previous = future.pop(); + + switch (previous.getUndoCommand()) { + + case AddCommand.COMMAND_WORD: + result = executeAdd((InputDeleteHistory) previous); + return new CommandResult(result); + + case DeleteCommand.COMMAND_WORD: + result = executeDelete((InputAddHistory) previous); + return new CommandResult(result); + + case EditCommand.COMMAND_WORD: + result = executeEdit((InputEditHistory) previous); + return new CommandResult(result); + + case ClearCommand.COMMAND_WORD: + result = executeClear((InputClearHistory)previous); + return new CommandResult(result); + + case MarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + return new CommandResult(result); + + case UnmarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + return new CommandResult(result); + } + return null; + } + + private String executeMark(InputMarkHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.markFloatingTask(previous.getTaskToMark(), previous.getMarkWhat()); + return "Redo mark successful"; + } catch (FloatingTaskNotFoundException | FloatingTaskMarkedException | FloatingTaskUnmarkedException e) { + assert false : "not possible"; + } + } + else { + try { + model.markDeadline(previous.getDeadlineToMark(), previous.getMarkWhat()); + return "Redo mark successful"; + } catch (DeadlineNotFoundException | DeadlineMarkedException | DeadlineUnmarkedException e) { + assert false: "not possible"; + } + } + return "Redo Failed"; + } + + private String executeClear(InputClearHistory previous) { + System.out.println(previous.getFloatingTask().getInternalList().isEmpty()); + ReadOnlyMalitio previousModel = new Malitio(previous.getFloatingTask(), previous.getDeadline(), previous.getEvent(), previous.getTag()); + model.resetData(previousModel); + return "Redo clear successful."; + + } + + private String executeEdit(InputEditHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.editFloatingTask(previous.getEditedTask(), previous.getTaskToEdit()); + return ("Redo successful. Redo edit from" + previous.getTaskToEdit().toString() + " to "+ previous.getEditedTask().toString()); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } + + else if (previous.getType().equals("deadline")) { + try { + model.editDeadline(previous.getEditedDeadline(), previous.getDeadlineToEdit()); + return ("Redo successful. Redo edit from" + previous.getDeadlineToEdit().toString() + " to "+ previous.getEditedDeadline().toString()); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } + else { + try { + model.editEvent(previous.getEditedEvent(), previous.getEventToEdit()); + return ("Redo successful. Redo edit from" + previous.getEventToEdit().toString() + " to "+ previous.getEditedEvent().toString()); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Redo Failed"; + } + + public String executeAdd(InputDeleteHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.addFloatingTaskAtSpecificPlace(previous.getFloatingTask(), previous.getPositionOfFloatingTask()); + return "Redo successful. Redo delete Floating Task: " + previous.getFloatingTask().toString(); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.addDeadline(previous.getDeadline()); + return "Redo successful. Redo delete Deadline: " + previous.getDeadline().toString(); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } + } else { + try { + model.addEvent(previous.getEvent()); + return "Redo successful. Redo delete Event: " + previous.getEvent().toString(); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } + } + return "Redo failed"; + } + + public String executeDelete(InputAddHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.deleteTask(previous.getFloatingTask()); + return "Redo Successful: Redo add Floating Task: " + previous.getFloatingTask().toString(); + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.deleteTask(previous.getDeadline()); + return "Redo Successful. Redo add Deadline: " + previous.getDeadline().toString(); + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } else { + try { + model.deleteTask(previous.getEvent()); + return "Redo successful. Redo add Event: " + previous.getEvent().toString(); + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Redo Failed"; + } +} +``` +###### \java\seedu\malitio\logic\commands\UndoCommand.java +``` java +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public String result; + + @Override + public CommandResult execute() { + + Stack history = model.getHistory(); + if (history.isEmpty()) { + return new CommandResult("No action to undo!"); + } + InputHistory previous = history.pop(); + + switch (previous.getUndoCommand()) { + + case AddCommand.COMMAND_WORD: + result = executeAdd((InputDeleteHistory) previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case DeleteCommand.COMMAND_WORD: + result = executeDelete((InputAddHistory) previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case EditCommand.COMMAND_WORD: + result = executeEdit((InputEditHistory) previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case ClearCommand.COMMAND_WORD: + result = executeClear((InputClearHistory)previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case MarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case UnmarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + } + return null; + } + + private String executeMark(InputMarkHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.markFloatingTask(previous.getTaskToMark(), previous.getMarkWhat()); + return "Undo mark successful"; + } catch (FloatingTaskNotFoundException | FloatingTaskMarkedException | FloatingTaskUnmarkedException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.markDeadline(previous.getDeadlineToMark(), previous.getMarkWhat()); + return "Undo mark successful"; + } catch (DeadlineNotFoundException | DeadlineMarkedException | DeadlineUnmarkedException e) { + assert false: "not possible"; + } + } else { + try { + model.markEvent(previous.getEventToMark(), previous.getMarkWhat()); + return "Undo mark successful"; + } catch (EventNotFoundException | EventMarkedException | EventUnmarkedException e) { + assert false: "not possible"; + } + } + return "Undo Failed"; + } + + private String executeClear(InputClearHistory previous) { + System.out.println(previous.getFloatingTask().getInternalList().isEmpty()); + ReadOnlyMalitio previousModel = new Malitio(previous.getFloatingTask(), previous.getDeadline(), previous.getEvent(), previous.getTag()); + model.resetData(previousModel); + return "Undo clear successful."; + + } + + private String executeEdit(InputEditHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.editFloatingTask(previous.getEditedTask(), previous.getTaskToEdit()); + return ("Undo edit successful. Revert edit from " + previous.getTaskToEdit().toString() + " to "+ previous.getEditedTask().toString()); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } + + else if (previous.getType().equals("deadline")) { + try { + model.editDeadline(previous.getEditedDeadline(), previous.getDeadlineToEdit()); + return ("Undo edit successful. Revert edit from " + previous.getDeadlineToEdit().toString() + " to "+ previous.getEditedDeadline().toString()); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } + else { + try { + model.editEvent(previous.getEditedEvent(), previous.getEventToEdit()); + return ("Undo edit successful. Revert edit from " + previous.getEventToEdit().toString() + " to "+ previous.getEditedEvent().toString()); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Undo Failed"; + } + + public String executeAdd(InputDeleteHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.addFloatingTaskAtSpecificPlace(previous.getFloatingTask(), previous.getPositionOfFloatingTask()); + return "Successful. Undo delete Floating Task: " + previous.getFloatingTask().toString(); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.addDeadline(previous.getDeadline()); + return "Successful. Undo delete Deadline: " + previous.getDeadline().toString(); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } + } else { + try { + model.addEvent(previous.getEvent()); + return "Successful. Undo delete Event: " + previous.getEvent().toString(); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } + } + return "Undo failed"; + } + + public String executeDelete(InputAddHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.deleteTask(previous.getFloatingTask()); + return "Successful: Undo add Floating Task: " + previous.getFloatingTask().toString(); + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.deleteTask(previous.getDeadline()); + return "Successful. Undo add Deadline: " + previous.getDeadline().toString(); + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } else { + try { + model.deleteTask(previous.getEvent()); + return "Successful. Undo add Event: " + previous.getEvent().toString(); + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Undo Failed"; + } + + /** + * A method to show all panels on the model. + */ + private void showAllPanels() { + model.updateFilteredTaskListToShowAll(); + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + } +} +``` +###### \java\seedu\malitio\model\history\InputAddHistory.java +``` java +public class InputAddHistory extends InputHistory { + + private ReadOnlyFloatingTask floatingTask; + private ReadOnlyDeadline deadline; + private ReadOnlyEvent event; + private String type; + + public InputAddHistory(FloatingTask target) { + this.commandForUndo = "delete"; + this.floatingTask = target; + this.type = "floating task"; + } + + public InputAddHistory(Deadline target) { + this.commandForUndo = "delete"; + this.deadline = target; + this.type = "deadline"; + } + + public InputAddHistory(Event target) { + this.commandForUndo = "delete"; + this.event = target; + this.type = "event"; + + } + + public String getType() { + return type; + } + + public ReadOnlyFloatingTask getFloatingTask() { + return floatingTask; + } + + public ReadOnlyDeadline getDeadline() { + return deadline; + } + + public ReadOnlyEvent getEvent() { + return event; + } + +} +``` +###### \java\seedu\malitio\model\history\InputClearHistory.java +``` java +public class InputClearHistory extends InputHistory{ + + UniqueFloatingTaskList originalFloatingTaskList = new UniqueFloatingTaskList(); + UniqueDeadlineList originalDeadlineList = new UniqueDeadlineList(); + UniqueEventList originalEventList = new UniqueEventList(); + UniqueTagList originalTagList = new UniqueTagList(); + + public InputClearHistory(UniqueFloatingTaskList task, UniqueDeadlineList deadline, + UniqueEventList event, UniqueTagList tag) { + this.originalFloatingTaskList.getInternalList().addAll(task.getInternalList()); + this.originalDeadlineList.getInternalList().addAll(deadline.getInternalList()); + this.originalEventList.getInternalList().addAll(event.getInternalList()); + this.originalTagList.getInternalList().addAll(tag.getInternalList()); + this.commandForUndo = "clear"; + } + + public UniqueFloatingTaskList getFloatingTask() { + return originalFloatingTaskList; + } + + public UniqueDeadlineList getDeadline() { + return originalDeadlineList; + } + + public UniqueEventList getEvent() { + return originalEventList; + } + + public UniqueTagList getTag() { + return originalTagList; + } +} +``` +###### \java\seedu\malitio\model\history\InputDeleteHistory.java +``` java +public class InputDeleteHistory extends InputHistory { + private String name; + private String due; + private String start; + private String end; + private UniqueTagList tags; + private String type; + private int initialPositionOfFloatingTask; + + public InputDeleteHistory(ReadOnlyFloatingTask target, ObservableList observableList) { + this.commandForUndo = "add"; + this.name = target.getName().fullName; + this.tags = target.getTags(); + this.type = "floating task"; + this.initialPositionOfFloatingTask = observableList.indexOf(target); + } + + public InputDeleteHistory(ReadOnlyDeadline target) { + this.commandForUndo = "add"; + this.name = target.getName().fullName; + this.due = target.getDue().toString(); + this.tags = target.getTags(); + this.type = "deadline"; + } + + public InputDeleteHistory(ReadOnlyEvent target) { + this.commandForUndo = "add"; + this.name = target.getName().fullName; + this.start = target.getStart().toString(); + this.end = target.getEnd().toString(); + this.tags = target.getTags(); + this.type = "event"; + } + + public String getType() { + return type; + } + + public FloatingTask getFloatingTask() { + return new FloatingTask(new Name(name), new UniqueTagList(tags)); + } + + public int getPositionOfFloatingTask() { + return initialPositionOfFloatingTask; + } + + public Deadline getDeadline() { + try { + return new Deadline(new Name(name), new DateTime(due), new UniqueTagList(tags)); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + return null; + } + + public Event getEvent() { + try { + return new Event(new Name(name), new DateTime(start), new DateTime(end), new UniqueTagList(tags)); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + return null; + } +} +``` +###### \java\seedu\malitio\model\history\InputEditHistory.java +``` java +public class InputEditHistory extends InputHistory { + + private ReadOnlyFloatingTask taskToEdit; + private ReadOnlyDeadline deadlineToEdit; + private ReadOnlyEvent eventToEdit; + private FloatingTask editedTask; + private Deadline editedDeadline; + private Event editedEvent; + private String type; + + public InputEditHistory(FloatingTask editedTask, ReadOnlyFloatingTask taskToEdit) { + this.type = "floating task"; + this.commandForUndo = "edit"; + this.taskToEdit = editedTask; + String name = taskToEdit.getName().fullName; + UniqueTagList tags = taskToEdit.getTags(); + this.editedTask = new FloatingTask(new Name(name), tags); + } + + + public InputEditHistory(Deadline editedDeadline, ReadOnlyDeadline deadlineToEdit) { + this.type = "deadline"; + this.commandForUndo = "edit"; + this.deadlineToEdit = editedDeadline; + String name = deadlineToEdit.getName().fullName; + String due = deadlineToEdit.getDue().toString(); + UniqueTagList tags = deadlineToEdit.getTags(); + try { + this.editedDeadline = new Deadline(new Name(name), new DateTime(due), tags); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + } + + public InputEditHistory(Event editedEvent, ReadOnlyEvent eventToEdit) { + this.type = "event"; + this.commandForUndo = "edit"; + this.eventToEdit = editedEvent; + String name = eventToEdit.getName().fullName; + String start = eventToEdit.getStart().toString(); + String end = eventToEdit.getEnd().toString(); + UniqueTagList tags = eventToEdit.getTags(); + try { + this.editedEvent = new Event(new Name(name), new DateTime(start), new DateTime(end), tags); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + } + + public String getType() { + return type; + } + + public ReadOnlyFloatingTask getTaskToEdit() { + return taskToEdit; + } + + public ReadOnlyDeadline getDeadlineToEdit() { + return deadlineToEdit; + } + + public ReadOnlyEvent getEventToEdit() { + return eventToEdit; + } + + public FloatingTask getEditedTask() { + return editedTask; + } + + public Deadline getEditedDeadline() { + return editedDeadline; + } + + public Event getEditedEvent() { + return editedEvent; + } + +} +``` +###### \java\seedu\malitio\model\history\InputHistory.java +``` java +public abstract class InputHistory { + + protected String commandForUndo; + + public String getUndoCommand() { + return commandForUndo; + } + +} +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void addFloatingTask(FloatingTask task) throws DuplicateFloatingTaskException { + malitio.addFloatingTask(task); + history.add(new InputAddHistory(task)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void addFloatingTaskAtSpecificPlace(FloatingTask task, int index) throws DuplicateFloatingTaskException { + malitio.addFloatingTask(task, index); + history.add(new InputAddHistory(task)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void addDeadline(Deadline deadline) throws DuplicateDeadlineException { + malitio.addDeadline(deadline); + history.add(new InputAddHistory(deadline)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void addEvent(Event event) throws DuplicateEventException { + malitio.addEvent(event); + history.add(new InputAddHistory(event)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void editFloatingTask(FloatingTask edited, ReadOnlyFloatingTask beforeEdit) throws DuplicateFloatingTaskException, FloatingTaskNotFoundException { + malitio.editFloatingTask(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void editDeadline(Deadline edited, ReadOnlyDeadline beforeEdit) throws DuplicateDeadlineException, DeadlineNotFoundException { + malitio.editDeadline(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void editEvent(Event edited, ReadOnlyEvent beforeEdit) throws DuplicateEventException, EventNotFoundException { + malitio.editEvent(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateFilteredEventListToShowAll(); + indicateMalitioChanged(); + } +``` +###### \java\seedu\malitio\model\task\UniqueDeadlineList.java +``` java + /** + * Returns true if the list contains an equivalent deadline as the given argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyDeadline toCheck) { + assert toCheck!=null; + if (!internalList.contains(toCheck)) { + return false; + } + else { + int index = internalList.indexOf(toCheck); + return internalList.get(index).getTags().getInternalList().containsAll(toCheck.getTags().getInternalList()); + } + } + + /** + * Adds a task to the list. + * + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(Deadline toAdd) throws DuplicateDeadlineException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateDeadlineException(); + } + internalList.add(toAdd); + } + + public void edit(Deadline edited, ReadOnlyDeadline beforeEdit) throws DuplicateDeadlineException, DeadlineNotFoundException { + assert edited!=null; + assert beforeEdit!=null; + if (containsWithTags(edited)) { + throw new DuplicateDeadlineException(); + } + + if (!contains(beforeEdit)) { + throw new DeadlineNotFoundException(); + } + + internalList.remove(beforeEdit); + internalList.add(edited); + } + + public void complete(ReadOnlyDeadline deadlineToComplete) throws DeadlineCompletedException, DeadlineNotFoundException { + assert deadlineToComplete!=null; + + if (deadlineToComplete.getCompleted()) { + throw new DeadlineCompletedException(); + } + + if (!contains(deadlineToComplete)) { + throw new DeadlineNotFoundException(); + } + + deadlineToComplete.setCompleted(); + updateDeadlineList(deadlineToComplete); + } + + /** + * Marks the deadline in the list. + * + * @throws DuplicateDeadlineException if the task to add is a duplicate of an existing task in the list. + * @throws DeadlineMarkedException if the deadline is already marked. + * @throws DeadlineUnmarkedException if the deadline is already unmarked. + */ + public void mark(ReadOnlyDeadline deadlineToMark, boolean marked) + throws DeadlineNotFoundException, DeadlineMarkedException, DeadlineUnmarkedException { + if (deadlineToMark.isMarked() && marked) { + throw new DeadlineMarkedException(); + } else if (!deadlineToMark.isMarked() && !marked) { + throw new DeadlineUnmarkedException(); + } + + if (!contains(deadlineToMark)) { + throw new DeadlineNotFoundException(); + } + + deadlineToMark.setMarked(marked); + updateDeadlineList(deadlineToMark); + } + + private void updateDeadlineList(ReadOnlyDeadline deadlineToComplete) { + int indexToReplace = internalList.indexOf(deadlineToComplete); + internalList.remove(deadlineToComplete); + internalList.add(indexToReplace, (Deadline) deadlineToComplete); + } + + /** + * Removes the equivalent schedule from the list. + * + * @throws DeadlineNotFoundException if no such deadline could be found in the list. + */ + public boolean remove(ReadOnlyDeadline toRemove) throws DeadlineNotFoundException { + assert toRemove != null; + final boolean deadlineFoundAndDeleted = internalList.remove(toRemove); + if (!deadlineFoundAndDeleted) { + throw new DeadlineNotFoundException(); + } + return deadlineFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + +``` +###### \java\seedu\malitio\model\task\UniqueEventList.java +``` java + /** + * Returns true if the list contains an equivalent event as the given argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyEvent toCheck) { + assert toCheck!=null; + if (!internalList.contains(toCheck)) { + return false; + } + else { + int index = internalList.indexOf(toCheck); + return internalList.get(index).getTags().getInternalList().containsAll(toCheck.getTags().getInternalList()); + } + } + + /** + * Adds a task to the list. + * + * @throws DuplicateEventException if the event to add is a duplicate of an existing event in the list. + */ + public void add(Event toAdd) throws DuplicateEventException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateEventException(); + } + internalList.add(toAdd); + } + + public void edit(Event edited, ReadOnlyEvent beforeEdit) throws DuplicateEventException, EventNotFoundException { + assert edited!=null; + assert beforeEdit!=null; + if (containsWithTags(edited)) { + throw new DuplicateEventException(); + } + + if (!contains(beforeEdit)) { + throw new EventNotFoundException(); + } + + internalList.remove(beforeEdit); + internalList.add(edited); + } +``` +###### \java\seedu\malitio\model\task\UniqueFloatingTaskList.java +``` java + /** + * Returns true if the list contains an equivalent task as the given argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyFloatingTask toCheck) { + assert toCheck!=null; + if (!internalList.contains(toCheck)) { + return false; + } + else { + int index = internalList.indexOf(toCheck); + return internalList.get(index).getTags().getInternalList().containsAll(toCheck.getTags().getInternalList()); + } + } + + /** + * Adds a floating task to the list. + * + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(FloatingTask toAdd) throws DuplicateFloatingTaskException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateFloatingTaskException(); + } + internalList.add(toAdd); + } + + + /** + * Adds a floating task to the list at the given index + * + * @param toAdd + * @param index + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(FloatingTask toAdd, int index) throws DuplicateFloatingTaskException{ + assert toAdd != null; + assert index>=0; + if (contains(toAdd)) { + throw new DuplicateFloatingTaskException(); + } + internalList.add(index, toAdd); + } + + public void edit(FloatingTask edited, ReadOnlyFloatingTask beforeEdit) throws DuplicateFloatingTaskException, FloatingTaskNotFoundException { + assert edited!=null; + assert beforeEdit!=null; + if (containsWithTags(edited)) { + throw new DuplicateFloatingTaskException(); + } + + if (!contains(beforeEdit)) { + throw new FloatingTaskNotFoundException(); + } + + int indexToReplace = internalList.indexOf(beforeEdit); + internalList.remove(beforeEdit); + internalList.add(indexToReplace, edited); + } + + public void complete(ReadOnlyFloatingTask toComplete) throws FloatingTaskCompletedException, FloatingTaskNotFoundException { + assert toComplete != null; + if (toComplete.getCompleted()) { + throw new FloatingTaskCompletedException(); + } + + if (!contains(toComplete)) { + throw new FloatingTaskNotFoundException(); + } + toComplete.setCompleted(); + updateFloatingTaskList(toComplete); + } + + /** + * Marks the task in the list. + * + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + * @throws FloatingTaskMarkedException if the deadline is already marked. + * @throws FloatingTaskUnmarkedException if the deadline is already unmarked. + */ + public void mark(ReadOnlyFloatingTask taskToMark, boolean marked) + throws FloatingTaskNotFoundException, FloatingTaskMarkedException, FloatingTaskUnmarkedException { + if (taskToMark.isMarked() && marked) { + throw new FloatingTaskMarkedException(); + } else if (!taskToMark.isMarked() && !marked) { + throw new FloatingTaskUnmarkedException(); + } + + if (!contains(taskToMark)) { + throw new FloatingTaskNotFoundException(); + } + taskToMark.setMarked(marked); + updateFloatingTaskList(taskToMark); + } + + private void updateFloatingTaskList(ReadOnlyFloatingTask toComplete) { + int indexToReplace = internalList.indexOf(toComplete); + internalList.remove(toComplete); + internalList.add(indexToReplace, (FloatingTask) toComplete); + } + + /** + * Removes the equivalent task from the list. + * + * @throws FloatingTaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyFloatingTask toRemove) throws FloatingTaskNotFoundException { + assert toRemove != null; + final boolean taskFoundAndDeleted = internalList.remove(toRemove); + if (!taskFoundAndDeleted) { + throw new FloatingTaskNotFoundException(); + } + return taskFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueFloatingTaskList // instanceof handles nulls + && this.internalList.equals( + ((UniqueFloatingTaskList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + +} +``` diff --git a/A0153006W.md b/A0153006W.md new file mode 100644 index 000000000000..6b3887554323 --- /dev/null +++ b/A0153006W.md @@ -0,0 +1,595 @@ +# A0153006W +###### \java\seedu\malitio\logic\commands\ListCommand.java +``` java + */ +public class ListCommand extends Command { + + public static final String COMMAND_WORD = "list"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Lists specified type of task to Malitio\n" + + "Parameters: [events|deadlines|tasks] [DATETIME]\n" + + "Example: " + COMMAND_WORD + " deadlines " + "sunday midnight"; + + public static final String ALL_MESSAGE_SUCCESS = "Listed all tasks"; + public static final String TASK_MESSAGE_SUCCESS = "Listed floating tasks"; + public static final String DEADLINE_MESSAGE_SUCCESS = "Listed deadlines"; + public static final String EVENT_MESSAGE_SUCCESS = "Listed events"; + + private String taskType = ""; + private DateTime timeKeyWord = null; + + public ListCommand() {} + + public ListCommand(String args) throws IllegalValueException { + if (args.matches("(floating )?tasks?.*")) { + this.taskType = "tasks"; + return; + } + else if (args.matches("deadlines?.*")) { + this.taskType = "deadlines"; + args = args.replaceAll("deadlines?\\s*", ""); + } + else if (args.matches("events?.*")) { + this.taskType = "events"; + args = args.replaceAll("events?\\s*", ""); + } + if (!args.isEmpty()) { + timeKeyWord = new DateTime(args); + } + } + + @Override + public CommandResult execute() { + if (taskType.equals("tasks")) { + model.updateFilteredTaskListToShowAll(); + return new CommandResult(TASK_MESSAGE_SUCCESS); + } else if (taskType.equals("deadlines")) { + if (timeKeyWord != null) { + model.updateFilteredDeadlineList(timeKeyWord); + } else { + model.updateFilteredDeadlineListToShowAll(); + } + return new CommandResult(DEADLINE_MESSAGE_SUCCESS); + } else if (taskType.equals("events")) { + if (timeKeyWord != null) { + model.updateFilteredEventList(timeKeyWord); + } else { + model.updateFilteredEventListToShowAll(); + } + return new CommandResult(EVENT_MESSAGE_SUCCESS); + } else { + if (timeKeyWord != null) { + model.updateFilteredDeadlineList(timeKeyWord); + model.updateFilteredEventList(timeKeyWord); + } else { + model.updateFilteredTaskListToShowAll(); + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + } + return new CommandResult(ALL_MESSAGE_SUCCESS); + } + } +} +``` +###### \java\seedu\malitio\logic\commands\MarkCommand.java +``` java + */ +public class MarkCommand extends Command { + + public static final String COMMAND_WORD = "mark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Marks specified task or deadline as priority in Malitio\n" + + "Parameters: INDEX\n" + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_MARK_SUCCESS = "Task has been marked as priority"; + + private final int targetIndex; + private final char taskType; + + public MarkCommand(char taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + if (!(taskType == 'f' || taskType == 'd' || taskType == 'e')) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + if (taskType == 'f') { + model.getFuture().clear(); + return executeMarkFloatingTask(); + } else if (taskType == 'd') { + model.getFuture().clear(); + return executeMarkDeadline(); + } else { + model.getFuture().clear(); + return executeMarkEvent(); + } + } + + private CommandResult executeMarkFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markFloatingTask(taskToMark, true); + } catch (FloatingTaskNotFoundException e) { + assert false : "The target floating task cannot be missing"; + } catch (FloatingTaskMarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (FloatingTaskUnmarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeMarkDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markDeadline(deadlineToMark, true); + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (DeadlineMarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (DeadlineUnmarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeMarkEvent() { + UnmodifiableObservableList lastShownList = model.getFilteredEventList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyEvent eventToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markEvent(eventToMark, true); + } catch (EventNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (EventMarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (EventUnmarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } +} +``` +###### \java\seedu\malitio\logic\commands\UnmarkCommand.java +``` java + */ +public class UnmarkCommand extends Command { + + public static final String COMMAND_WORD = "unmark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Unmarks specified task or deadline as priority in Malitio\n" + + "Parameters: INDEX\n" + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_MARK_SUCCESS = "Task has been unmarked as priority"; + + private final int targetIndex; + private final char taskType; + + public UnmarkCommand(char taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + if (!(taskType == 'f' || taskType == 'd' || taskType == 'e')) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + if (taskType == 'f') { + model.getFuture().clear(); + return executeUnmarkFloatingTask(); + } else if (taskType == 'd') { + model.getFuture().clear(); + return executeUnmarkDeadline(); + } else { + model.getFuture().clear(); + return executeUnmarkEvent(); + } + } + + private CommandResult executeUnmarkFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markFloatingTask(taskToMark, false); + } catch (FloatingTaskNotFoundException e) { + assert false : "The target floating task cannot be missing"; + } catch (FloatingTaskUnmarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (FloatingTaskMarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeUnmarkDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markDeadline(deadlineToMark, false); + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (DeadlineUnmarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (DeadlineMarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeUnmarkEvent() { + UnmodifiableObservableList lastShownList = model.getFilteredEventList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyEvent eventToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markEvent(eventToMark, false); + } catch (EventNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (EventUnmarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (EventMarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } +} +``` +###### \java\seedu\malitio\logic\parser\Parser.java +``` java + */ + private Command prepareAdd(String args){ + final Matcher matcher = TASK_DATA_ARGS_FORMAT.matcher(args.trim()); + boolean hasStart = false; + boolean hasEnd = false; + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + try { + String name = matcher.group("name"); + + String deadline = getDeadlineFromArgs(StringUtil.removeTagsFromString(name)); + if (!deadline.isEmpty()) { + name = name.replaceAll("by " + deadline, ""); + } + + String start = getStartFromArgs(StringUtil.removeTagsFromString(name)); + if (!start.isEmpty()) { + name = name.replaceAll("start " + start, ""); + hasStart = true; + } + + String end = getEndFromArgs(StringUtil.removeTagsFromString(name)); + if (!end.isEmpty()) { + name = name.replaceAll("end " + end, ""); + hasEnd = true; + } + + if (!deadline.isEmpty() && !hasStart && !hasEnd) { + return new AddCommand( + name, + deadline, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (hasStart && hasEnd) { + return new AddCommand( + name, + start, + end, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (hasStart ^ hasEnd) { + return new IncorrectCommand("Expecting start and end times\nExample: start thursday 800 end thursday 900"); + } else if (!deadline.isEmpty() && hasStart || !deadline.isEmpty() && hasEnd) { + return new IncorrectCommand("Expecting either a duedate or start and end time."); + + } + return new AddCommand( + name, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the edit task command. + * + * @param arguments + * @return the prepared command + */ + private Command prepareEdit(String args) { + final Matcher matcher = EDIT_DATA_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + String name = matcher.group("name"); + if (name.equals("") && getTagsFromArgs(matcher.group("tagArguments")).isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + String deadline = getDeadlineFromArgs(name); + if (!deadline.isEmpty()) { + name = name.replaceAll(" by " + deadline, ""); + } + + String start = getStartFromArgs(name); + if (!start.isEmpty()) { + name = name.replaceAll(" start " + start, ""); + } + + String end = getEndFromArgs(name); + if (!end.isEmpty()) { + name = name.replaceAll(" end " + end, ""); + } + + if (taskType == 'd') { + return new EditCommand( + taskType, + taskNum, + name, + deadline, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (taskType == 'e') { + return new EditCommand( + taskType, + taskNum, + name, + start, + end, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } + return new EditCommand( + taskType, + taskNum, + name, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the complete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareComplete(String args) { + final Matcher matcher = COMPLETE_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new CompleteCommand(taskType,taskNum); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the delete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareDelete(String args) { + String index = parseIndex(args); + if(index.isEmpty()) { + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new DeleteCommand(Character.toString(taskType), taskNum); + } + + /** + * Parses arguments in the context of the mark task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareMark(String args) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkCommand.MESSAGE_USAGE)); + } + String index = parseIndex(args); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + return new MarkCommand(taskType, taskNum); + } + + /** + * Parses arguments in the context of the unmark task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareUnmark(String args) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnmarkCommand.MESSAGE_USAGE)); + } + String index = parseIndex(args); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnmarkCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + return new UnmarkCommand(taskType, taskNum); + } + + /** + * Parses arguments in the context of the find task command. + * + * @param args full command args string + * @return the prepared command +``` +###### \java\seedu\malitio\logic\parser\Parser.java +``` java + */ + private Command prepareList(String args) { + if (args.isEmpty()) { + return new ListCommand(); + } + try { + args = args.trim().toLowerCase(); + return new ListCommand(args); + } catch (IllegalValueException ive) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE)); + } + } + + /** + * Returns the specified index as a String in the {@code command} + */ + private String parseIndex(String command) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim()); + if (!matcher.matches()) { + return ""; + } + String index = command.trim().toLowerCase(); + return index; + } + + /** + * Extracts the task's deadline from the command's arguments string. + */ + private static String getDeadlineFromArgs(String args) throws IllegalValueException { + int byIndex = args.lastIndexOf("by"); + String deadline = ""; + if(byIndex > 0 && byIndex < args.length() - 2) { + deadline = args.substring(byIndex + 3); + } + return deadline; + } + + /** + * Extracts the task's event start from the command's arguments string. + */ + private static String getStartFromArgs(String args) throws IllegalValueException { + int startIndex = args.lastIndexOf("start"); + int endIndex = args.lastIndexOf("end"); + if (startIndex > 0 && endIndex > 0) { + return args.substring(startIndex + 6, endIndex - 1); + } else if (startIndex > 0 && endIndex < 0) { + return args.substring(startIndex + 6); + } else { + return ""; + } + } + + /** + * Extracts the task's event end from the command's arguments string. + */ + private static String getEndFromArgs(String args) throws IllegalValueException { + int endIndex = args.lastIndexOf("end"); + if (endIndex > 0) { + return args.substring(endIndex + 4); + } else { + return ""; + } + } + + /** + * Extracts the new task's tags from the add command's tag arguments string. + * Merges duplicate tag strings. +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void markFloatingTask(ReadOnlyFloatingTask taskToMark, boolean marked) + throws FloatingTaskNotFoundException, FloatingTaskMarkedException, FloatingTaskUnmarkedException { + malitio.markTask(taskToMark, marked); + history.add(new InputMarkHistory(taskToMark, marked)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void markDeadline(ReadOnlyDeadline deadlineToMark, boolean marked) + throws DeadlineNotFoundException, DeadlineMarkedException, DeadlineUnmarkedException { + malitio.markDeadline(deadlineToMark, marked); + history.add(new InputMarkHistory(deadlineToMark, marked)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void markEvent(ReadOnlyEvent eventToMark, boolean marked) + throws EventNotFoundException, EventMarkedException, EventUnmarkedException { + malitio.markEvent(eventToMark, marked); + history.add(new InputMarkHistory(eventToMark, marked)); + updateFilteredEventListToShowAll(); + indicateMalitioChanged(); + } +``` diff --git a/Collate-TUI.jar b/Collate-TUI.jar new file mode 100644 index 000000000000..50bdfe6902f8 Binary files /dev/null and b/Collate-TUI.jar differ diff --git a/Collate.bat b/Collate.bat new file mode 100644 index 000000000000..fe9495364100 --- /dev/null +++ b/Collate.bat @@ -0,0 +1,5 @@ +java -jar Collate-TUI.jar collate from src/main to collated/main include java, fxml, css + +java -jar Collate-TUI.jar collate from src/test to collated/test include java + +java -jar Collate-TUI.jar collate from docs to collated/docs include md, html \ No newline at end of file diff --git a/LICENSE b/LICENSE index 39b3478982c3..eddc9532c817 100644 --- a/LICENSE +++ b/LICENSE @@ -2,11 +2,11 @@ MIT License Copyright (c) 2016 Software Engineering Education - FOSS Resources -Permission is hereby granted, free of charge, to any person obtaining a copy +Permission is hereby granted, free of charge, to any task obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is +copies of the Software, and to permit tasks to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all diff --git a/README.md b/README.md index 249a00b3899c..d7cf4a8f24d8 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -[![Build Status](https://travis-ci.org/se-edu/addressbook-level4.svg?branch=master)](https://travis-ci.org/se-edu/addressbook-level4) -[![Coverage Status](https://coveralls.io/repos/github/se-edu/addressbook-level4/badge.svg?branch=master)](https://coveralls.io/github/se-edu/addressbook-level4?branch=master) +[![Build Status](https://travis-ci.org/CS2103AUG2016-T13-C3/main.svg?branch=master)](https://travis-ci.org/CS2103AUG2016-T13-C3/main) +[![Coverage Status](https://coveralls.io/repos/github/CS2103AUG2016-T13-C3/main/badge.svg?branch)](https://coveralls.io/github/CS2103AUG2016-T13-C3/main?branch) -# Address Book (Level 4) +# Malitio -
+
-* This is a desktop Address Book application. It has a GUI but most of the user interactions happen using +* This is a desktop to-do list application. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface). * It is a Java sample application intended for students learning Software Engineering while using Java as the main programming language. @@ -28,7 +28,11 @@ #### Acknowledgements * Some parts of this sample application were inspired by the excellent - [Java FX tutorial](http://code.makery.ch/library/javafx-8-tutorial/) by *Marco Jakob*. + [Java FX tutorial](http://code.makery.ch/library/javafx-8-tutorial/) by *Marco Jakob*. + +* Base code by SE-EDU initiative at https://github.com/se-edu/ + +* Natty is used to parse date time. Copyright (c) 2010 Joseph Stelmach -#### Licence : [MIT](LICENSE) +#### License : [MIT](LICENSE) diff --git a/a0126633j.md b/a0126633j.md new file mode 100644 index 000000000000..9c2ca2029c2f --- /dev/null +++ b/a0126633j.md @@ -0,0 +1,366 @@ +# a0126633j +###### \java\seedu\malitio\commons\events\storage\DataStorageFileChangedEvent.java +``` java +public class DataStorageFileChangedEvent extends BaseEvent { + + public String dataFilePath; + + public DataStorageFileChangedEvent(String dataFilePath) { + this.dataFilePath = dataFilePath; + } + + @Override + public String toString() { + return "Directory of storage changed to " + dataFilePath; + } + +} +``` +###### \java\seedu\malitio\commons\util\ConfigUtil.java +``` java + public static void changeMalitioSaveDirectory(String dataFilePath) { + Config existingConfig; + + try { + Optional config = readConfig(Config.DEFAULT_CONFIG_FILE); + existingConfig = config.orElse(new Config()); + } catch (DataConversionException e) { + logger.warning("Could not find existing Config file. Created a new Config file."); + existingConfig = new Config(); + } + + existingConfig.setMalitioFilePath(dataFilePath); + try { + saveConfig(existingConfig, Config.DEFAULT_CONFIG_FILE); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + } + +} +``` +###### \java\seedu\malitio\commons\util\FileUtil.java +``` java + public static void deleteFile(String filePath) throws IOException { + Path path = Paths.get(filePath); + Files.deleteIfExists(path); + } + + public static boolean twoFilePathsAreEqual(String filePath1, String filePath2) throws IOException { + try { + if(new File(filePath1).getCanonicalPath().compareTo(new File(filePath2).getCanonicalPath()) == 0) { + return true; + } + } catch (IOException e1) { + throw new IOException("Fail to compare two file paths"); + } + return false; + } +} +``` +###### \java\seedu\malitio\commons\util\StringUtil.java +``` java + public static String removeSlashesAtBeginningOfString(String arg) { + while(arg.charAt(0) == '/') { + arg = arg.substring(1); + } + return arg; + } +} +``` +###### \java\seedu\malitio\logic\commands\DeleteCommand.java +``` java + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the task identified by the index used in the last task listing.\n" + + "Parameters: INDEX \n" + "Example: " + COMMAND_WORD + " D1"; + + public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted %1$s"; + + private static final String[] TYPES_OF_TASKS = {"f","d", "e"}; + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + private final int targetIndex; + private final String taskType; + + public DeleteCommand(String taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + + assert(Arrays.asList(TYPES_OF_TASKS).contains(taskType)); + + int sizeOfList = 0; + + switch (taskType) { + case FLOATING_TASK_KEYWORD: + UnmodifiableObservableList lastShownFloatingTaskList = model.getFilteredFloatingTaskList(); + sizeOfList = lastShownFloatingTaskList.size(); + break; + case DEADLINE_KEYWORD: + UnmodifiableObservableList lastShownDeadlineList = model.getFilteredDeadlineList(); + sizeOfList = lastShownDeadlineList.size(); + break; + case EVENT_KEYWORD: + UnmodifiableObservableList lastShownEventList = model.getFilteredEventList(); + sizeOfList = lastShownEventList.size(); + } + + if (sizeOfList < targetIndex || targetIndex < 1) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + switch (taskType) { + case FLOATING_TASK_KEYWORD: + ReadOnlyFloatingTask taskToDelete = model.getFilteredFloatingTaskList().get(targetIndex - 1); + executeDelete(taskToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + + case DEADLINE_KEYWORD: + ReadOnlyDeadline deadlineToDelete = model.getFilteredDeadlineList().get(targetIndex - 1); + executeDelete(deadlineToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, deadlineToDelete)); + + default: + assert(taskType.equals(EVENT_KEYWORD)); + ReadOnlyEvent eventToDelete = model.getFilteredEventList().get(targetIndex - 1); + executeDelete(eventToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, eventToDelete)); + } + } + + /** + * overloading executeDelete function for different tasks + * + */ + private void executeDelete(ReadOnlyFloatingTask taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target floating task cannot be missing"; + } + } + + private void executeDelete(ReadOnlyDeadline taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } + } + + private void executeDelete(ReadOnlyEvent taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (EventNotFoundException pnfe) { + assert false : "The target event cannot be missing"; + } + } +} +``` +###### \java\seedu\malitio\logic\commands\FindCommand.java +``` java + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds [specified] tasks whose names contain any of " + + "the specified keywords and displays them as a list with index numbers.\n" + + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " [f/d/e] adjust bring chill"; + + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + private final Set keywords; + private final String typeOfTask; + + public FindCommand(String type, Set keywords) { + this.keywords = keywords; + this.typeOfTask = type; + } + + @Override + public CommandResult execute() { + + switch (typeOfTask) { + case FLOATING_TASK_KEYWORD: + model.updateFilteredTaskList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredFloatingTaskList().size())); + case DEADLINE_KEYWORD: + model.updateFilteredDeadlineList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredDeadlineList().size())); + case EVENT_KEYWORD: + model.updateFilteredEventList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredEventList().size())); + + default: //find in all lists + model.updateFilteredTaskList(keywords); + model.updateFilteredDeadlineList(keywords); + model.updateFilteredEventList(keywords); + return new CommandResult(getMessageForTaskListShownSummary( + model.getFilteredFloatingTaskList().size() + + model.getFilteredDeadlineList().size() + + model.getFilteredEventList().size())); + } + } + +} +``` +###### \java\seedu\malitio\logic\commands\SaveCommand.java +``` java +/** + * Allows the user to change the directory of save file. Old file in old directory will be deleted. + * The new directory will be remembered next time the App starts. + */ +public class SaveCommand extends Command { + + private static final Logger logger = LogsCenter.getLogger(SaveCommand.class); + + public static final String COMMAND_WORD = "save"; + + public static final String MESSAGE_DIRECTORY_EXAMPLE = "C://Users/User PC/Downloads/"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a task to Malitio.\n" + + "Parameters: File Directory\n" + + "Example: " + COMMAND_WORD + + " " + MESSAGE_DIRECTORY_EXAMPLE; + + public static final String MESSAGE_SAVE_SUCCESSFUL = "Malitio data will be saved in %s from now onwards."; + + public static final String MESSAGE_INVALID_DIRECTORY = "The directory is invalid!\nExample: "; + + public static final char FILE_PATH_IDENTIFIER = '/'; + + private final String dataFilePath; + + /** + * Initialises dataFilePath to the input if the input ends with '/', else set dataFilePath to null + * + */ + public SaveCommand(String dataFilePath) { + if(dataFilePath.charAt(dataFilePath.length() - 1) == FILE_PATH_IDENTIFIER) { + this.dataFilePath = StringUtil.removeSlashesAtBeginningOfString(dataFilePath.trim()) + Config.DEFAULT_FILE_NAME; + } else { + this.dataFilePath = null; + } + } + + @Override + public CommandResult execute() { + if(!isValidFilePath()) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(MESSAGE_INVALID_DIRECTORY + MESSAGE_DIRECTORY_EXAMPLE); + } + EventsCenter.getInstance().post(new DataStorageFileChangedEvent(dataFilePath)); + ConfigUtil.changeMalitioSaveDirectory(dataFilePath); + model.dataFilePathChanged(); + + return new CommandResult(String.format(MESSAGE_SAVE_SUCCESSFUL, dataFilePath)); + } + + /** + * Checks if the input by user is a valid file path + */ + private boolean isValidFilePath() { + if(dataFilePath == null || dataFilePath.contains("\\")) { + return false; + } + + File file = new File(dataFilePath); + try { + if(!FileUtil.createFile(file)) { + logger.warning("File already exists"); + } + return true; + } catch (IOException e) { + return false; + } + } +} +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void dataFilePathChanged() { + logger.info("Data storage file path changed, updating.."); + indicateMalitioChanged(); + } + +``` +###### \java\seedu\malitio\model\task\DateTime.java +``` java +public class DateTime { + public static final String MESSAGE_DATETIME_CONSTRAINTS = "Unrecognised date and time!"; + + private Date date; + + private static DateFormat outputFormatter = new SimpleDateFormat("MM-dd-yyyy HH:mm"); + + /** + * Converts the string that contains date information into Date + * + * @throws IllegalValueException if the format of date is unrecognised + */ + public DateTime(String date) throws IllegalValueException { + + this.date = DateParser.parse(date); + if (this.date == null) { + throw new IllegalValueException(MESSAGE_DATETIME_CONSTRAINTS); + } + } + + public String toString() { + String newDateString = outputFormatter.format(date); + return newDateString; + } + + public int compareTo(DateTime dateTime) { + return date.compareTo(dateTime.getDate()); + } + + public Date getDate() { + return date; + } +} +``` +###### \java\seedu\malitio\storage\StorageManager.java +``` java + @Subscribe + public void handleDataStorageFileChangedEvent(DataStorageFileChangedEvent event) throws DataConversionException, IOException { + String oldDataFilePath = malitioStorage.getMalitioFilePath(); + Optional dataToBeTransferred = malitioStorage.readMalitio(); + malitioStorage = new XmlMalitioStorage(event.dataFilePath); + + if(FileUtil.twoFilePathsAreEqual(oldDataFilePath, this.malitioStorage.getMalitioFilePath())) { + return; + } + + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Data storage file path changed, updating..")); + + try { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Old data file is being deleted.")); + FileUtil.deleteFile(oldDataFilePath); + } catch (IOException e) { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Failed to delete old data file.")); + } + } +} +``` +###### \java\seedu\malitio\ui\StatusBarFooter.java +``` java + @Subscribe + public void handleDataStorageFileChangedEvent(DataStorageFileChangedEvent event) { + setSaveLocation(event.dataFilePath); + } +} +``` diff --git a/build.gradle b/build.gradle index 46b06c1e42ec..5482c8cac05c 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,9 @@ allprojects { compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonDataTypeVersion" compile "com.google.guava:guava:$guavaVersion" + compile files('main/lib/natty-0.12.jar') + compile 'com.joestelmach:natty:0.12' + testCompile "junit:junit:$junitVersion" testCompile "org.testfx:testfx-core:$testFxVersion" @@ -74,10 +77,10 @@ allprojects { } shadowJar { - archiveName = "addressbook.jar" + archiveName = "malitio.jar" manifest { - attributes "Main-Class": "seedu.address.MainApp" + attributes "Main-Class": "seedu.malitio.MainApp" } destinationDir = file("${buildDir}/jar/") @@ -113,8 +116,8 @@ tasks.coveralls { onlyIf { System.env.'CI' } } -class AddressBookTest extends Test { - public AddressBookTest() { +class malitioTest extends Test { + public malitioTest() { forkEvery = 1 systemProperty 'testfx.setup.timeout', '60000' } @@ -128,7 +131,7 @@ class AddressBookTest extends Test { } } -task guiTests(type: AddressBookTest) { +task guiTests(type: malitioTest) { include 'guitests/**' jacoco { @@ -137,8 +140,8 @@ task guiTests(type: AddressBookTest) { } -task nonGuiTests(type: AddressBookTest) { - include 'seedu/address/**' +task nonGuiTests(type: malitioTest) { + include 'seedu/malitio/**' jacoco { destinationFile = new File("${buildDir}/jacoco/test.exec") @@ -146,7 +149,7 @@ task nonGuiTests(type: AddressBookTest) { } // Test mode depends on whether headless task has been run -task allTests(type: AddressBookTest) { +task allTests(type: malitioTest) { jacoco { destinationFile = new File("${buildDir}/jacoco/test.exec") } diff --git a/collated/docs/A0122460W.md b/collated/docs/A0122460W.md new file mode 100644 index 000000000000..c41ed9644cd0 --- /dev/null +++ b/collated/docs/A0122460W.md @@ -0,0 +1,18 @@ +# A0122460W +###### \UserGuide.md +``` md +#### Completing a floating task or deadline: `complete` +complete the specified floating task or deadline from Malitio by striking out them.
+Format: `complete f/d+INDEX` + +> Complete the floating task or deadline at the specified `INDEX`. + The index refers to the index number shown in the most recent listing.
+ The index **must have either 'f' or 'd' as a prefix and also a positive integer** eg. f1, d2, ... + +Examples: + `complete f2`
+ Complete the 2nd floating task in Malitio. + `complete d1`
+ Complete the 1st deadline in Malitio. + +``` diff --git a/collated/docs/A0129595N.md b/collated/docs/A0129595N.md new file mode 100644 index 000000000000..86065def38b6 --- /dev/null +++ b/collated/docs/A0129595N.md @@ -0,0 +1,263 @@ +# A0129595N +###### \DeveloperGuide.md +``` md +### Model component + +
+ +**API** : [`Model.java`](../src/main/java/seedu/address/model/Model.java) + +The `Model`, +* stores a `UserPref` object that represents the user's preferences. +* stores the malitio data. +* stores the history and future of data-changing commands in stacks of InputHistory. +* exposes a `UnmodifiableObservableList`, `UnmodifiableObservableList`, `UnmodifiableObservableList` that can be 'observed' e.g. the UI can be bound to this list + so that the UI automatically updates when the data in any of the list change. +* exposes the two stacks of InputHistory (history and future) for access by UndoCommand and RedoCommand. +* does not depend on any of the other three components. + +### Storage component + +
+ +**API** : [`Storage.java`](../src/main/java/seedu/address/storage/Storage.java) + +The `Storage` component, +* can save `UserPref` objects in json format and read it back. +* can save the malitio data in xml format and read it back. + +### Common classes + +Classes used by multiple components are in the `seedu.malitio.commons` package. + +## Implementation + +### Logging + +We are using `java.util.logging` package for logging. The `LogsCenter` class is used to manage the logging levels +and logging destinations. + +* The logging level can be controlled using the `logLevel` setting in the configuration file + (See [Configuration](#configuration)) +* The `Logger` for a class can be obtained using `LogsCenter.getLogger(Class)` which will log messages according to + the specified logging level +* Currently log messages are output through: `Console` and to a `.log` file. + +**Logging Levels** + +* `SEVERE` : Critical problem detected which may possibly cause the termination of the application +* `WARNING` : Can continue, but with caution +* `INFO` : Information showing the noteworthy actions by the App +* `FINE` : Details that is not usually noteworthy but may be useful in debugging + e.g. print the actual list instead of just its size + +### Configuration + +Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file +(default: `config.json`): + + +## Testing + +Tests can be found in the `./src/test/java` folder. + +**In Eclipse**: +* To run all tests, right-click on the `src/test/java` folder and choose + `Run as` > `JUnit Test` +* To run a subset of tests, you can right-click on a test package, test class, or a test and choose + to run as a JUnit test. + +**Using Gradle**: +* See [UsingGradle.md](UsingGradle.md) for how to run tests using Gradle. + +We have two types of tests: + +1. **GUI Tests** - These are _System Tests_ that test the entire App by simulating user actions on the GUI. + These are in the `guitests` package. + +2. **Non-GUI Tests** - These are tests not involving the GUI. They include, + 1. _Unit tests_ targeting the lowest level methods/classes.
+ e.g. `seedu.address.commons.UrlUtilTest` + 2. _Integration tests_ that are checking the integration of multiple code units + (those code units are assumed to be working).
+ e.g. `seedu.address.storage.StorageManagerTest` + 3. Hybrids of unit and integration tests. These test are checking multiple code units as well as + how the are connected together.
+ e.g. `seedu.address.logic.LogicManagerTest` + +**Headless GUI Testing** : +Thanks to the [TestFX](https://github.com/TestFX/TestFX) library we use, + our GUI tests can be run in the _headless_ mode. + In the headless mode, GUI tests do not show up on the screen. + That means the developer can do other things on the Computer while the tests are running.
+ See [UsingGradle.md](UsingGradle.md#running-tests) to learn how to run tests in headless mode. + +#### Troubleshooting tests + **Problem: Tests fail because NullPointException when AssertionError is expected** + * Reason: Assertions are not enabled for JUnit tests. + This can happen if you are not using a recent Eclipse version (i.e. _Neon_ or later) + * Solution: Enable assertions in JUnit tests as described + [here](http://stackoverflow.com/questions/2522897/eclipse-junit-ea-vm-option).
+ Delete run configurations created when you ran tests earlier. + +## Dev Ops + +### Build Automation + +See [UsingGradle.md](UsingGradle.md) to learn how to use Gradle for build automation. + +### Continuous Integration + +We use [Travis CI](https://travis-ci.org/) to perform _Continuous Integration_ on our projects. +See [UsingTravis.md](UsingTravis.md) for more details. + +### Making a Release + +Here are the steps to create a new release. + + 1. Generate a JAR file [using Gradle](UsingGradle.md#creating-the-jar-file). + 2. Tag the repo with the version number. e.g. `v0.1` + 2. [Crete a new release using GitHub](https://help.github.com/articles/creating-releases/) + and upload the JAR file your created. + +### Managing Dependencies + +A project often depends on third-party libraries. For example, malitio depends on the +[Jackson library](http://wiki.fasterxml.com/JacksonHome) for XML parsing. Managing these _dependencies_ +can be automated using Gradle. For example, Gradle can download the dependencies automatically, which +is better than these alternatives.
+a. Include those libraries in the repo (this bloats the repo size)
+b. Require developers to download those libraries manually (this creates extra work for developers)
+ +## Appendix A : User Stories + +Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` + + +Priority | As a ... | I want to ... | So that I can... +-------- | :-------- | :--------- | :----------- +`* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App +`* * *` | new user | view more information about a particular command | learn how to use various commands +`* * *` | user | add a new floating task | +`* * *` | user | add a new event | +`* * *` | user | add a new deadline | +`* * *` | user | delete a floating task | remove an entry that I no longer need or have completed +`* * *` | user | delete an event | remove an event that has passed or has been cancelled +`* * *` | user | delete a deadline | remove a deadline that has passed or been removed +`* * *` | user | find a(n) event/deadline/floating task by name | locate details of the event/deadline/task without having to go through the entire list +`* * *` | user | edit a(n) event/deadline/floating task | update it or correct any errors +`* * *` | user | set a(n) event/deadlines/floating task as a priority | know which one should be completed first +`* * *` | user | view all tasks | plan ahead depending on availablity +`* * *` | user | view all tasks on specified day(s) | plan ahead +`* * *` | user | undo my last action | rectify any mistakes I made +`* *` | user | be notified of upcoming events | remember important events +`* *` | user | be warned of clashing events | avoid a clash in my schedule +`* *` | advanced user | use shorter version of a commands | type a command faster +`*` | advanced user | switch between light/dark mode | Enhance visibility or save power +`*` | user | know the weather forecast on days with events | be prepared in case of wet weather + + +## Appendix B : Use Cases + +(For all use cases below, the **System** is `Malitio` and the **Actor** is the `User`, unless specified otherwise) + +#### Use case: Delete a floating task + +**MSS** + +1. User requests to delete a specific floating task in the floating task list +2. Malitio deletes the floating task
+Use case ends. + +**Extensions** + +1a. The given index is invalid + +> 1a1. Malitio shows an error message
+ Use case restarts at step 1 + +#### Use case: Edit a floating task + +**MSS** + +1. User requests to edit a specific floating task by its index and input changes +2. Malitio implement the specified edit and reflect the change to user
+Use case ends. + +**Extensions** +1a. The given index is invalid + +> 1a1. Malitio shows an error message
+ Use case restarts at step 1 + +## Appendix C : Non Functional Requirements + +1. Should work on any [mainstream OS](#mainstream-os) as long as it has Java `1.8.0_60` or higher installed. +2. Should be able to hold up to 1000 floating tasks, events and deadlines combined. +3. Should come with automated unit tests and open source code. +4. Should favor DOS style commands over Unix-style commands. + +{More to be added} + +## Appendix D : Glossary + +##### Mainstream OS + +> Windows, Linux, Unix, OS-X + +##### Floating task + +> A task that has no deadline + +## Appendix E : Product Survey + +**Desktop Reminder**
+Desktop Reminder is a desktop application and can be run in offline mode. It has an alert system which will ring at a specified time (determined by user) to alert the user of upcoming tasks. However, the drawback of this application is that it does not minimize to the system tray when user clicked on the 'X' button but instead, gets minimized as a window which will hover on top of the taskbar. + +**Google Calendar and Google Task**
+Google Calender displays the event and on the right side, Google Task shows the tasks which needs completion. This view enables user to see what task they have on which days easily. However, a drawback is that google task is rather simple and does not have a lot of features. + +**Remember The Milk**
+Remember The Milk (RTM) allows users to categorize task which is useful if users want to group related task together. However, a drawback of RTM is that it does not allow users to input specific reminders before the events (e.g. 10minutes before, 1 day before, etc) but only have a general reminder which will be through email to the task. Since there is a mobile app for this, the inability to generate mobile reminders (e.g. alarm or notification) is a potential hindrance especially to users who do not check their emails often. + +``` +###### \UserGuide.md +``` md + +#### Edit a task : `edit` +Edits the specified task from the to-do list.
+Edit Floating Task Format: `edit 'f'INDEX [TASK_NAME] [t/TAG]`
+Edit Deadline Format: `edit 'd'INDEX [TASK_NAME] [by DATE/TIME] [t/TAG]`
+Edit Event Format `edit 'e'INDEX [TASK_NAME] [start DATE/TIME] [end DATE/TIME]`
+To remove all tags from a task without adding new ones, use the parameter: t/null
+ + +> Edits the task at the specified `INDEX` with the given one or more parameters. + The index refers to the index number shown in the most recent listing.
+ The index **must have either 'f','d' or 'e' as a prefix and also a positive integer** f1, e2, d3, ...
+ At least one of the optional parameters must be present
+ The prefix is not case sensitive.
+ The edit function can only edit the details within the same type of task.
+ No changing of task type supported.
+ +Examples: + `edit e1 end 12-21 2359`
+ Edit the 1st event in the to-do list replacing its original end time with 12-21 2359.
+ `edit 1 n/lunch with mom`
+ Edits the 1st task in the results of the `find` or ‘ command.
+ Need to put at least one field +``` +###### \UserGuide.md +``` md +#### Undo the most recent action: `undo` +Undo the most recent data-related command and reverts Malitio to previous state.
+Data-related commands include add, delete, edit and clear.
+Format: `undo` + +#### Redo the most recent action: `redo` +Redo the most recent data-related command and reverts Malitio to previous state before undo.
+Redo will no longer be possible after a new data-related command is executed.
+Data-related commands include add, delete, edit and clear.
+Format: `redo` + +``` diff --git a/collated/docs/A0153006W.md b/collated/docs/A0153006W.md new file mode 100644 index 000000000000..d512fcd1ab69 --- /dev/null +++ b/collated/docs/A0153006W.md @@ -0,0 +1,52 @@ +# A0153006W +###### \DeveloperGuide.md +``` md +### Logic component + +
+ +**API** : [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java) + +1. `Logic` uses the `Parser` class to parse the user command. +2. This results in a `Command` object which is executed by the `LogicManager`. +3. The command execution can affect the `Model` (e.g. adding a task) and/or raise events. +4. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. + +Given below is the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` + API call.
+
+ +``` +###### \UserGuide.md +``` md + +#### Listing tasks: `list` +Shows a list of everything in the to-do list.
+Format: `list [tasks|events|deadlines]` + +Shows a list of all events and/or deadlines in the to-do list on and after that date.
+Format: `list [deadlines|events] DATE/TIME` + +Examples: +* `list` +* `list deadlines` +* `list deadlines 05-10 1400` +* `list 05-10 1400` +``` +###### \UserGuide.md +``` md + +#### Marking as priority : `mark` +Marks the specified task in the to-do list
+Format: `mark INDEX` + +Examples: +* `mark f1` + +#### Marking as priority : `unmark` +Unmarks the specified task in the to-do list
+Format: `unmark INDEX` + +Examples: +* `unmark f1` +``` diff --git a/collated/docs/a0126633j.md b/collated/docs/a0126633j.md new file mode 100644 index 000000000000..eec01ff13f50 --- /dev/null +++ b/collated/docs/a0126633j.md @@ -0,0 +1,52 @@ +# a0126633j +###### \UserGuide.md +``` md +#### Finding tasks: `find` +Finds all input entries specified by the type (deadlines/ floating tasks/ events) whose names contain any of the given keywords.
+If the type is not specified, all entries containing the keyword will be displayed.
+Format: `find [f|d|e] KEYWORD [MORE KEYWORDS]` + +> * The search is case insensitive. +> * The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` +> * Only the task names are searched. +> * Only full words will be matched e.g. `Han` will not match `Hans` +> * Task matching at least one keyword will be returned (i.e. `OR` search). + e.g. `Hans` will match `Hans Bo` + +Examples: +* `find f lunch`
+ Returns `lunch with mom in floating task` +* `find d lunch`
+ Returns `lunch with mom in deadlines` +* `find e lunch`
+ Returns `lunch with mom in events` +* `find lunch dinner breakfast`
+ Returns any tasks having names `lunch`, `dinner`, or `breakfast` + + +#### Deleting a task : `delete` +Deletes the specified task from the to-do list. Irreversible.
+ +Format: `delete INDEX` + +> Deletes the task at the specified `INDEX`. + The index **must have either 'f','d' or 'e' as a prefix and also a positive integer** f1, e2, d3, ...
+ +Examples: +* `delete e2`
+ Deletes the 2nd task in the currently showing events list. +* `delete f1`
+ Deletes the 1st task in the currently showing floating task list. +``` +###### \UserGuide.md +``` md +#### Specifying location of local data file: `save` +Users can specify which directory to save their data file. Only valid directory will be created if it does not exist already.
+The old data file will automatically be deleted. +Format: `save DIRECTORY` +* DIRECTORY can be in absolute or relative format + +Example: +* `save C://Users`
+ Saves data in C://Users/malitio.xml +``` diff --git a/collated/main/A0122460W.md b/collated/main/A0122460W.md new file mode 100644 index 000000000000..61a2cfd13dc0 --- /dev/null +++ b/collated/main/A0122460W.md @@ -0,0 +1,104 @@ +# A0122460W +###### \java\seedu\malitio\logic\commands\CompleteCommand.java +``` java +public class CompleteCommand extends Command{ + + public static final String COMMAND_WORD = "complete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": complete the task or deadline identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d' and a positive integer) " + + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_COMPLETED_TASK = "The floating task is completed in Malitio"; + + public static final String MESSAGE_COMPLETED_DEADLINE = "The deadline is completed in Malitio"; + + public static final String MESSAGE_COMPLETED_TASK_SUCCESS = "Successfully completed floating task."; + + public static final String MESSAGE_COMPLETED_DEADLINE_SUCCESS = "Successfully completed deadline."; + + private final char taskType; + + private final int targetIndex; + + public CompleteCommand(char taskType, int targetIndex) throws IllegalValueException { + assert taskType == 'd' || taskType == 'f'; + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + CommandResult result; + if (taskType=='f') { + result = executeCompleteFloatingTask(); + model.getFuture().clear(); + return result; + } + else { + result = executeCompleteDeadline(); + model.getFuture().clear(); + return result; + } + } + + private CommandResult executeCompleteFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToComplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.completeFloatingTask(taskToComplete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } catch (UniqueFloatingTaskList.FloatingTaskCompletedException e) { + return new CommandResult(MESSAGE_COMPLETED_TASK); + } + return new CommandResult(String.format(MESSAGE_COMPLETED_TASK_SUCCESS, taskToComplete)); + } + + private CommandResult executeCompleteDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToComplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.completeDeadline(deadlineToComplete); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } catch (UniqueDeadlineList.DeadlineCompletedException e) { + return new CommandResult(MESSAGE_COMPLETED_DEADLINE); + } + return new CommandResult(String.format(MESSAGE_COMPLETED_DEADLINE_SUCCESS, deadlineToComplete)); + } + +} +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void completeFloatingTask(ReadOnlyFloatingTask taskToComplete) throws FloatingTaskCompletedException, FloatingTaskNotFoundException { + malitio.completeTask(taskToComplete); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void completeDeadline(ReadOnlyDeadline deadlineToEdit) throws DeadlineCompletedException, DeadlineNotFoundException { + malitio.completeDeadline(deadlineToEdit); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + +``` diff --git a/collated/main/A0129595N.md b/collated/main/A0129595N.md new file mode 100644 index 000000000000..54f09ec3af77 --- /dev/null +++ b/collated/main/A0129595N.md @@ -0,0 +1,1310 @@ +# A0129595N +###### \java\seedu\malitio\logic\commands\AddCommand.java +``` java +/** + * Adds a task to Malitio. + */ +public class AddCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": adds a task to Malitio. Task name cannot contain \'/\'. \n" + + "Parameters: NAME [by DEADLINE] [start STARTTIME end ENDTIME] [t/TAG]...\n" + + "Example: " + COMMAND_WORD + + " Pay John $100 by Oct 11 2359 t/oweMoney"; + + public static final String MESSAGE_SUCCESS = "New task added: %1$s"; + public static final String MESSAGE_DUPLICATE_TASK = "This floating task already exists in Malitio"; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists in Malitio"; + public static final String MESSAGE_DUPLICATE_DEADLINE ="This deadline already exists in Malitio"; + private FloatingTask toAddFloatingTask; + private Deadline toAddDeadline; + private Event toAddEvent; + + /** + * Convenience constructor for floating tasks using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAddFloatingTask = new FloatingTask( + new Name(name), + new UniqueTagList(tagSet) + ); + } + + /** + * Convenience constructor for deadlines using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + + public AddCommand(String name, String date, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAddDeadline = new Deadline( + new Name(name), + new DateTime(date), + new UniqueTagList(tagSet) + ); + } + + /** + * Convenience constructor for events using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, String start, String end, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + // check if start < end + this.toAddEvent = new Event( + new Name(name), + new DateTime(start), + new DateTime(end), + new UniqueTagList(tagSet) + ); + } + + /** + * Executes the command. It will clear the future stack so that no redo can be done. + */ + @Override + public CommandResult execute() { + assert model != null; + if (toAddFloatingTask!=null){ + try { + model.addFloatingTask(toAddFloatingTask); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddFloatingTask)); + } catch (UniqueFloatingTaskList.DuplicateFloatingTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } + } + else if (toAddDeadline != null){ + try { + model.addDeadline(toAddDeadline); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddDeadline)); + } catch (UniqueDeadlineList.DuplicateDeadlineException e) { + return new CommandResult(MESSAGE_DUPLICATE_DEADLINE); + } + } + else { + try { + model.addEvent(toAddEvent); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddEvent)); + } catch (UniqueEventList.DuplicateEventException e) { + return new CommandResult(MESSAGE_DUPLICATE_EVENT); + } + } + } +} +``` +###### \java\seedu\malitio\logic\commands\EditCommand.java +``` java +/** + * Edits a floating task/ deadline/ event identified using it's last displayed index from Malitio. + * Only the attribute(s) that require changes is(are) entered. + */ +public class EditCommand extends Command{ + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ":Edits the task identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d'/'e' and a positive integer) [NAME] [by NEWDATE] [START NEWDATE] [END NEWDATE]\n" + + "Example: " + COMMAND_WORD + " f1 New Name"; + + public static final String MESSAGE_DUPLICATE_TASK = "The intended edit correspond to a pre-existing floating task in Malitio"; + + public static final String MESSAGE_DUPLICATE_DEADLINE = "The intended edit correspond to a pre-existing deadline in Malitio"; + + public static final String MESSAGE_DUPLICATE_EVENT = "The intended edit correspond to a pre-existing event in Malitio"; + + public static final String MESSAGE_INVALID_EVENT = "Event must start before it ends!"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Successfully edited floating task.\nOld: %1$s\nNew: %2$s"; + + public static final String MESSAGE_EDIT_DEADLINE_SUCCESS = "Successfully edited deadline.\nOld: %1$s\nNew: %2$s"; + + public static final String MESSAGE_EDIT_EVENT_SUCCESS = "Successfully edited event.\nOld: %1$s\nNew: %2$s"; + + private final char taskType; + + private final int targetIndex; + + private FloatingTask editedTask; + + private Deadline editedDeadline; + + private Event editedEvent; + + private Name name; + + private DateTime due; + + private DateTime start; + + private DateTime end; + + private UniqueTagList tags; + +``` +###### \java\seedu\malitio\logic\commands\EditCommand.java +``` java + public EditCommand(char taskType, int targetIndex, String name, Set newTags) + throws IllegalValueException { + assert taskType == 'f'; + assert !name.equals("") || !newTags.isEmpty() ; + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + this.tags = processTags(newTags); + } + + public EditCommand(char taskType, int targetIndex, String name, String due, Set newTags) + throws IllegalValueException { + assert taskType == 'd'; + assert !name.equals("") || !due.equals("") || !newTags.isEmpty(); + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + if (!due.equals("")) { + this.due = new DateTime(due); + } + this.tags = processTags(newTags); + } + + public EditCommand(char taskType, int targetIndex, String name, String start, String end, Set newTags) + throws IllegalValueException { + assert taskType == 'e'; + assert !name.equals("") || !start.equals("") || !end.equals("") || !newTags.isEmpty(); + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + if (!start.equals("")) { + this.start = new DateTime(start); + } + if (!end.equals("")) { + this.end = new DateTime(end); + } + this.tags = processTags(newTags); + } + + + /** + * processTags return a UniqueTagList of tags but returns null if no tags were entered. + * @param newTags + * @return UniqueTagList or Null + * @throws IllegalValueException + */ + private UniqueTagList processTags(Set newTags) throws IllegalValueException { + if (!newTags.isEmpty() && newTags.toArray()[0].equals("null") && newTags.size()==1) { + return new UniqueTagList(); + } + else if (!newTags.isEmpty()){ + final Set tagSet = new HashSet<>(); + for (String tagName : newTags) { + tagSet.add(new Tag(tagName)); + } + return new UniqueTagList(tagSet); + } + else { + return null; + } + } + + /** + * fillInTheGaps will replace the task's attributes not entered by the user by extracting from the task to be edited . + * @param ReadOnly + */ + private void fillInTheGaps(ReadOnlyFloatingTask taskToEdit) { + if (this.name==null) { + this.name = taskToEdit.getName(); + } + if (this.tags==null) { + this.tags = taskToEdit.getTags(); + } + } + + private void fillInTheGaps(ReadOnlyDeadline deadlineToEdit) { + if (this.name==null) { + this.name = deadlineToEdit.getName(); + } + if (this.due==null) { + this.due = deadlineToEdit.getDue(); + } + if (this.tags==null) { + this.tags = deadlineToEdit.getTags(); + } + } + + private void fillInTheGaps(ReadOnlyEvent eventToEdit) { + if (this.name==null) { + this.name = eventToEdit.getName(); + } + if (this.start==null) { + this.start = eventToEdit.getStart(); + } + if (this.end==null) { + this.end = eventToEdit.getEnd(); + } + if (this.tags==null) { + this.tags = eventToEdit.getTags(); + } + } + @Override + public CommandResult execute() { + CommandResult result; + if (taskType=='f') { + result = executeEditFloatingTask(); + model.getFuture().clear(); + return result; + } + else if (taskType=='d') { + result = executeEditDeadline(); + model.getFuture().clear(); + return result; + } + else { + result = executeEditEvent(); + model.getFuture().clear(); + return result; + } + + } + + public CommandResult executeEditFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(taskToEdit); + editedTask = new FloatingTask(name,tags); + model.editFloatingTask(editedTask, taskToEdit); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } catch (UniqueFloatingTaskList.DuplicateFloatingTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit, editedTask)); + } + + public CommandResult executeEditDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(deadlineToEdit); + editedDeadline = new Deadline(name,due,tags); + model.editDeadline(editedDeadline, deadlineToEdit); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } catch (UniqueDeadlineList.DuplicateDeadlineException e) { + return new CommandResult(MESSAGE_DUPLICATE_DEADLINE); + } + return new CommandResult(String.format(MESSAGE_EDIT_DEADLINE_SUCCESS, deadlineToEdit, editedDeadline)); + } + + public CommandResult executeEditEvent() { + UnmodifiableObservableList lastShownList = model.getFilteredEventList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_EVENT_DISPLAYED_INDEX); + } + + ReadOnlyEvent eventToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(eventToEdit); + editedEvent = new Event(name, start, end, tags); + model.editEvent(editedEvent, eventToEdit); + } catch (EventNotFoundException pnfe) { + assert false : "The target event cannot be missing"; + } catch (DuplicateEventException e) { + return new CommandResult(MESSAGE_DUPLICATE_EVENT); + } catch (IllegalValueException e) { + return new CommandResult(MESSAGE_INVALID_EVENT); + } + return new CommandResult(String.format(MESSAGE_EDIT_EVENT_SUCCESS, eventToEdit, editedEvent)); + } + +} +``` +###### \java\seedu\malitio\logic\commands\RedoCommand.java +``` java +public class RedoCommand extends Command { + + public static final String COMMAND_WORD = "redo"; + public String result; + + @Override + public CommandResult execute() { + + Stack future = model.getFuture(); + if (future.isEmpty()) { + return new CommandResult("No action to redo!"); + } + InputHistory previous = future.pop(); + + switch (previous.getUndoCommand()) { + + case AddCommand.COMMAND_WORD: + result = executeAdd((InputDeleteHistory) previous); + return new CommandResult(result); + + case DeleteCommand.COMMAND_WORD: + result = executeDelete((InputAddHistory) previous); + return new CommandResult(result); + + case EditCommand.COMMAND_WORD: + result = executeEdit((InputEditHistory) previous); + return new CommandResult(result); + + case ClearCommand.COMMAND_WORD: + result = executeClear((InputClearHistory)previous); + return new CommandResult(result); + + case MarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + return new CommandResult(result); + + case UnmarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + return new CommandResult(result); + } + return null; + } + + private String executeMark(InputMarkHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.markFloatingTask(previous.getTaskToMark(), previous.getMarkWhat()); + return "Redo mark successful"; + } catch (FloatingTaskNotFoundException | FloatingTaskMarkedException | FloatingTaskUnmarkedException e) { + assert false : "not possible"; + } + } + else { + try { + model.markDeadline(previous.getDeadlineToMark(), previous.getMarkWhat()); + return "Redo mark successful"; + } catch (DeadlineNotFoundException | DeadlineMarkedException | DeadlineUnmarkedException e) { + assert false: "not possible"; + } + } + return "Redo Failed"; + } + + private String executeClear(InputClearHistory previous) { + System.out.println(previous.getFloatingTask().getInternalList().isEmpty()); + ReadOnlyMalitio previousModel = new Malitio(previous.getFloatingTask(), previous.getDeadline(), previous.getEvent(), previous.getTag()); + model.resetData(previousModel); + return "Redo clear successful."; + + } + + private String executeEdit(InputEditHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.editFloatingTask(previous.getEditedTask(), previous.getTaskToEdit()); + return ("Redo successful. Redo edit from" + previous.getTaskToEdit().toString() + " to "+ previous.getEditedTask().toString()); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } + + else if (previous.getType().equals("deadline")) { + try { + model.editDeadline(previous.getEditedDeadline(), previous.getDeadlineToEdit()); + return ("Redo successful. Redo edit from" + previous.getDeadlineToEdit().toString() + " to "+ previous.getEditedDeadline().toString()); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } + else { + try { + model.editEvent(previous.getEditedEvent(), previous.getEventToEdit()); + return ("Redo successful. Redo edit from" + previous.getEventToEdit().toString() + " to "+ previous.getEditedEvent().toString()); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Redo Failed"; + } + + public String executeAdd(InputDeleteHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.addFloatingTaskAtSpecificPlace(previous.getFloatingTask(), previous.getPositionOfFloatingTask()); + return "Redo successful. Redo delete Floating Task: " + previous.getFloatingTask().toString(); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.addDeadline(previous.getDeadline()); + return "Redo successful. Redo delete Deadline: " + previous.getDeadline().toString(); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } + } else { + try { + model.addEvent(previous.getEvent()); + return "Redo successful. Redo delete Event: " + previous.getEvent().toString(); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } + } + return "Redo failed"; + } + + public String executeDelete(InputAddHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.deleteTask(previous.getFloatingTask()); + return "Redo Successful: Redo add Floating Task: " + previous.getFloatingTask().toString(); + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.deleteTask(previous.getDeadline()); + return "Redo Successful. Redo add Deadline: " + previous.getDeadline().toString(); + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } else { + try { + model.deleteTask(previous.getEvent()); + return "Redo successful. Redo add Event: " + previous.getEvent().toString(); + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Redo Failed"; + } +} +``` +###### \java\seedu\malitio\logic\commands\UndoCommand.java +``` java +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public String result; + + @Override + public CommandResult execute() { + + Stack history = model.getHistory(); + if (history.isEmpty()) { + return new CommandResult("No action to undo!"); + } + InputHistory previous = history.pop(); + + switch (previous.getUndoCommand()) { + + case AddCommand.COMMAND_WORD: + result = executeAdd((InputDeleteHistory) previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case DeleteCommand.COMMAND_WORD: + result = executeDelete((InputAddHistory) previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case EditCommand.COMMAND_WORD: + result = executeEdit((InputEditHistory) previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case ClearCommand.COMMAND_WORD: + result = executeClear((InputClearHistory)previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case MarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + case UnmarkCommand.COMMAND_WORD: + result = executeMark((InputMarkHistory)previous); + model.getFuture().push(history.pop()); + showAllPanels(); + return new CommandResult(result); + + } + return null; + } + + private String executeMark(InputMarkHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.markFloatingTask(previous.getTaskToMark(), previous.getMarkWhat()); + return "Undo mark successful"; + } catch (FloatingTaskNotFoundException | FloatingTaskMarkedException | FloatingTaskUnmarkedException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.markDeadline(previous.getDeadlineToMark(), previous.getMarkWhat()); + return "Undo mark successful"; + } catch (DeadlineNotFoundException | DeadlineMarkedException | DeadlineUnmarkedException e) { + assert false: "not possible"; + } + } else { + try { + model.markEvent(previous.getEventToMark(), previous.getMarkWhat()); + return "Undo mark successful"; + } catch (EventNotFoundException | EventMarkedException | EventUnmarkedException e) { + assert false: "not possible"; + } + } + return "Undo Failed"; + } + + private String executeClear(InputClearHistory previous) { + System.out.println(previous.getFloatingTask().getInternalList().isEmpty()); + ReadOnlyMalitio previousModel = new Malitio(previous.getFloatingTask(), previous.getDeadline(), previous.getEvent(), previous.getTag()); + model.resetData(previousModel); + return "Undo clear successful."; + + } + + private String executeEdit(InputEditHistory previous) { + if (previous.getType().equals("floating task")) { + try { + model.editFloatingTask(previous.getEditedTask(), previous.getTaskToEdit()); + return ("Undo edit successful. Revert edit from " + previous.getTaskToEdit().toString() + " to "+ previous.getEditedTask().toString()); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } + + else if (previous.getType().equals("deadline")) { + try { + model.editDeadline(previous.getEditedDeadline(), previous.getDeadlineToEdit()); + return ("Undo edit successful. Revert edit from " + previous.getDeadlineToEdit().toString() + " to "+ previous.getEditedDeadline().toString()); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } + else { + try { + model.editEvent(previous.getEditedEvent(), previous.getEventToEdit()); + return ("Undo edit successful. Revert edit from " + previous.getEventToEdit().toString() + " to "+ previous.getEditedEvent().toString()); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Undo Failed"; + } + + public String executeAdd(InputDeleteHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.addFloatingTaskAtSpecificPlace(previous.getFloatingTask(), previous.getPositionOfFloatingTask()); + return "Successful. Undo delete Floating Task: " + previous.getFloatingTask().toString(); + } catch (DuplicateFloatingTaskException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.addDeadline(previous.getDeadline()); + return "Successful. Undo delete Deadline: " + previous.getDeadline().toString(); + } catch (DuplicateDeadlineException e) { + assert false : "not possible"; + } + } else { + try { + model.addEvent(previous.getEvent()); + return "Successful. Undo delete Event: " + previous.getEvent().toString(); + } catch (DuplicateEventException e) { + assert false : "not possible"; + } + } + return "Undo failed"; + } + + public String executeDelete(InputAddHistory previous) { + + if (previous.getType().equals("floating task")) { + try { + model.deleteTask(previous.getFloatingTask()); + return "Successful: Undo add Floating Task: " + previous.getFloatingTask().toString(); + } catch (FloatingTaskNotFoundException e) { + assert false : "not possible"; + } + } else if (previous.getType().equals("deadline")) { + try { + model.deleteTask(previous.getDeadline()); + return "Successful. Undo add Deadline: " + previous.getDeadline().toString(); + } catch (DeadlineNotFoundException e) { + assert false : "not possible"; + } + } else { + try { + model.deleteTask(previous.getEvent()); + return "Successful. Undo add Event: " + previous.getEvent().toString(); + } catch (EventNotFoundException e) { + assert false : "not possible"; + } + } + return "Undo Failed"; + } + + /** + * A method to show all panels on the model. + */ + private void showAllPanels() { + model.updateFilteredTaskListToShowAll(); + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + } +} +``` +###### \java\seedu\malitio\model\history\InputAddHistory.java +``` java +public class InputAddHistory extends InputHistory { + + private ReadOnlyFloatingTask floatingTask; + private ReadOnlyDeadline deadline; + private ReadOnlyEvent event; + private String type; + + public InputAddHistory(FloatingTask target) { + this.commandForUndo = "delete"; + this.floatingTask = target; + this.type = "floating task"; + } + + public InputAddHistory(Deadline target) { + this.commandForUndo = "delete"; + this.deadline = target; + this.type = "deadline"; + } + + public InputAddHistory(Event target) { + this.commandForUndo = "delete"; + this.event = target; + this.type = "event"; + + } + + public String getType() { + return type; + } + + public ReadOnlyFloatingTask getFloatingTask() { + return floatingTask; + } + + public ReadOnlyDeadline getDeadline() { + return deadline; + } + + public ReadOnlyEvent getEvent() { + return event; + } + +} +``` +###### \java\seedu\malitio\model\history\InputClearHistory.java +``` java +public class InputClearHistory extends InputHistory{ + + UniqueFloatingTaskList originalFloatingTaskList = new UniqueFloatingTaskList(); + UniqueDeadlineList originalDeadlineList = new UniqueDeadlineList(); + UniqueEventList originalEventList = new UniqueEventList(); + UniqueTagList originalTagList = new UniqueTagList(); + + public InputClearHistory(UniqueFloatingTaskList task, UniqueDeadlineList deadline, + UniqueEventList event, UniqueTagList tag) { + this.originalFloatingTaskList.getInternalList().addAll(task.getInternalList()); + this.originalDeadlineList.getInternalList().addAll(deadline.getInternalList()); + this.originalEventList.getInternalList().addAll(event.getInternalList()); + this.originalTagList.getInternalList().addAll(tag.getInternalList()); + this.commandForUndo = "clear"; + } + + public UniqueFloatingTaskList getFloatingTask() { + return originalFloatingTaskList; + } + + public UniqueDeadlineList getDeadline() { + return originalDeadlineList; + } + + public UniqueEventList getEvent() { + return originalEventList; + } + + public UniqueTagList getTag() { + return originalTagList; + } +} +``` +###### \java\seedu\malitio\model\history\InputDeleteHistory.java +``` java +public class InputDeleteHistory extends InputHistory { + private String name; + private String due; + private String start; + private String end; + private UniqueTagList tags; + private String type; + private int initialPositionOfFloatingTask; + + public InputDeleteHistory(ReadOnlyFloatingTask target, ObservableList observableList) { + this.commandForUndo = "add"; + this.name = target.getName().fullName; + this.tags = target.getTags(); + this.type = "floating task"; + this.initialPositionOfFloatingTask = observableList.indexOf(target); + } + + public InputDeleteHistory(ReadOnlyDeadline target) { + this.commandForUndo = "add"; + this.name = target.getName().fullName; + this.due = target.getDue().toString(); + this.tags = target.getTags(); + this.type = "deadline"; + } + + public InputDeleteHistory(ReadOnlyEvent target) { + this.commandForUndo = "add"; + this.name = target.getName().fullName; + this.start = target.getStart().toString(); + this.end = target.getEnd().toString(); + this.tags = target.getTags(); + this.type = "event"; + } + + public String getType() { + return type; + } + + public FloatingTask getFloatingTask() { + return new FloatingTask(new Name(name), new UniqueTagList(tags)); + } + + public int getPositionOfFloatingTask() { + return initialPositionOfFloatingTask; + } + + public Deadline getDeadline() { + try { + return new Deadline(new Name(name), new DateTime(due), new UniqueTagList(tags)); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + return null; + } + + public Event getEvent() { + try { + return new Event(new Name(name), new DateTime(start), new DateTime(end), new UniqueTagList(tags)); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + return null; + } +} +``` +###### \java\seedu\malitio\model\history\InputEditHistory.java +``` java +public class InputEditHistory extends InputHistory { + + private ReadOnlyFloatingTask taskToEdit; + private ReadOnlyDeadline deadlineToEdit; + private ReadOnlyEvent eventToEdit; + private FloatingTask editedTask; + private Deadline editedDeadline; + private Event editedEvent; + private String type; + + public InputEditHistory(FloatingTask editedTask, ReadOnlyFloatingTask taskToEdit) { + this.type = "floating task"; + this.commandForUndo = "edit"; + this.taskToEdit = editedTask; + String name = taskToEdit.getName().fullName; + UniqueTagList tags = taskToEdit.getTags(); + this.editedTask = new FloatingTask(new Name(name), tags); + } + + + public InputEditHistory(Deadline editedDeadline, ReadOnlyDeadline deadlineToEdit) { + this.type = "deadline"; + this.commandForUndo = "edit"; + this.deadlineToEdit = editedDeadline; + String name = deadlineToEdit.getName().fullName; + String due = deadlineToEdit.getDue().toString(); + UniqueTagList tags = deadlineToEdit.getTags(); + try { + this.editedDeadline = new Deadline(new Name(name), new DateTime(due), tags); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + } + + public InputEditHistory(Event editedEvent, ReadOnlyEvent eventToEdit) { + this.type = "event"; + this.commandForUndo = "edit"; + this.eventToEdit = editedEvent; + String name = eventToEdit.getName().fullName; + String start = eventToEdit.getStart().toString(); + String end = eventToEdit.getEnd().toString(); + UniqueTagList tags = eventToEdit.getTags(); + try { + this.editedEvent = new Event(new Name(name), new DateTime(start), new DateTime(end), tags); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + } + + public String getType() { + return type; + } + + public ReadOnlyFloatingTask getTaskToEdit() { + return taskToEdit; + } + + public ReadOnlyDeadline getDeadlineToEdit() { + return deadlineToEdit; + } + + public ReadOnlyEvent getEventToEdit() { + return eventToEdit; + } + + public FloatingTask getEditedTask() { + return editedTask; + } + + public Deadline getEditedDeadline() { + return editedDeadline; + } + + public Event getEditedEvent() { + return editedEvent; + } + +} +``` +###### \java\seedu\malitio\model\history\InputHistory.java +``` java +public abstract class InputHistory { + + protected String commandForUndo; + + public String getUndoCommand() { + return commandForUndo; + } + +} +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void addFloatingTask(FloatingTask task) throws DuplicateFloatingTaskException { + malitio.addFloatingTask(task); + history.add(new InputAddHistory(task)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void addFloatingTaskAtSpecificPlace(FloatingTask task, int index) throws DuplicateFloatingTaskException { + malitio.addFloatingTask(task, index); + history.add(new InputAddHistory(task)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void addDeadline(Deadline deadline) throws DuplicateDeadlineException { + malitio.addDeadline(deadline); + history.add(new InputAddHistory(deadline)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void addEvent(Event event) throws DuplicateEventException { + malitio.addEvent(event); + history.add(new InputAddHistory(event)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void editFloatingTask(FloatingTask edited, ReadOnlyFloatingTask beforeEdit) throws DuplicateFloatingTaskException, FloatingTaskNotFoundException { + malitio.editFloatingTask(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void editDeadline(Deadline edited, ReadOnlyDeadline beforeEdit) throws DuplicateDeadlineException, DeadlineNotFoundException { + malitio.editDeadline(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void editEvent(Event edited, ReadOnlyEvent beforeEdit) throws DuplicateEventException, EventNotFoundException { + malitio.editEvent(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateFilteredEventListToShowAll(); + indicateMalitioChanged(); + } +``` +###### \java\seedu\malitio\model\task\UniqueDeadlineList.java +``` java + /** + * Returns true if the list contains an equivalent deadline as the given argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyDeadline toCheck) { + assert toCheck!=null; + if (!internalList.contains(toCheck)) { + return false; + } + else { + int index = internalList.indexOf(toCheck); + return internalList.get(index).getTags().getInternalList().containsAll(toCheck.getTags().getInternalList()); + } + } + + /** + * Adds a task to the list. + * + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(Deadline toAdd) throws DuplicateDeadlineException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateDeadlineException(); + } + internalList.add(toAdd); + } + + public void edit(Deadline edited, ReadOnlyDeadline beforeEdit) throws DuplicateDeadlineException, DeadlineNotFoundException { + assert edited!=null; + assert beforeEdit!=null; + if (containsWithTags(edited)) { + throw new DuplicateDeadlineException(); + } + + if (!contains(beforeEdit)) { + throw new DeadlineNotFoundException(); + } + + internalList.remove(beforeEdit); + internalList.add(edited); + } + + public void complete(ReadOnlyDeadline deadlineToComplete) throws DeadlineCompletedException, DeadlineNotFoundException { + assert deadlineToComplete!=null; + + if (deadlineToComplete.getCompleted()) { + throw new DeadlineCompletedException(); + } + + if (!contains(deadlineToComplete)) { + throw new DeadlineNotFoundException(); + } + + deadlineToComplete.setCompleted(); + updateDeadlineList(deadlineToComplete); + } + + /** + * Marks the deadline in the list. + * + * @throws DuplicateDeadlineException if the task to add is a duplicate of an existing task in the list. + * @throws DeadlineMarkedException if the deadline is already marked. + * @throws DeadlineUnmarkedException if the deadline is already unmarked. + */ + public void mark(ReadOnlyDeadline deadlineToMark, boolean marked) + throws DeadlineNotFoundException, DeadlineMarkedException, DeadlineUnmarkedException { + if (deadlineToMark.isMarked() && marked) { + throw new DeadlineMarkedException(); + } else if (!deadlineToMark.isMarked() && !marked) { + throw new DeadlineUnmarkedException(); + } + + if (!contains(deadlineToMark)) { + throw new DeadlineNotFoundException(); + } + + deadlineToMark.setMarked(marked); + updateDeadlineList(deadlineToMark); + } + + private void updateDeadlineList(ReadOnlyDeadline deadlineToComplete) { + int indexToReplace = internalList.indexOf(deadlineToComplete); + internalList.remove(deadlineToComplete); + internalList.add(indexToReplace, (Deadline) deadlineToComplete); + } + + /** + * Removes the equivalent schedule from the list. + * + * @throws DeadlineNotFoundException if no such deadline could be found in the list. + */ + public boolean remove(ReadOnlyDeadline toRemove) throws DeadlineNotFoundException { + assert toRemove != null; + final boolean deadlineFoundAndDeleted = internalList.remove(toRemove); + if (!deadlineFoundAndDeleted) { + throw new DeadlineNotFoundException(); + } + return deadlineFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + +``` +###### \java\seedu\malitio\model\task\UniqueEventList.java +``` java + /** + * Returns true if the list contains an equivalent event as the given argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyEvent toCheck) { + assert toCheck!=null; + if (!internalList.contains(toCheck)) { + return false; + } + else { + int index = internalList.indexOf(toCheck); + return internalList.get(index).getTags().getInternalList().containsAll(toCheck.getTags().getInternalList()); + } + } + + /** + * Adds a task to the list. + * + * @throws DuplicateEventException if the event to add is a duplicate of an existing event in the list. + */ + public void add(Event toAdd) throws DuplicateEventException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateEventException(); + } + internalList.add(toAdd); + } + + public void edit(Event edited, ReadOnlyEvent beforeEdit) throws DuplicateEventException, EventNotFoundException { + assert edited!=null; + assert beforeEdit!=null; + if (containsWithTags(edited)) { + throw new DuplicateEventException(); + } + + if (!contains(beforeEdit)) { + throw new EventNotFoundException(); + } + + internalList.remove(beforeEdit); + internalList.add(edited); + } +``` +###### \java\seedu\malitio\model\task\UniqueFloatingTaskList.java +``` java + /** + * Returns true if the list contains an equivalent task as the given argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyFloatingTask toCheck) { + assert toCheck!=null; + if (!internalList.contains(toCheck)) { + return false; + } + else { + int index = internalList.indexOf(toCheck); + return internalList.get(index).getTags().getInternalList().containsAll(toCheck.getTags().getInternalList()); + } + } + + /** + * Adds a floating task to the list. + * + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(FloatingTask toAdd) throws DuplicateFloatingTaskException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateFloatingTaskException(); + } + internalList.add(toAdd); + } + + + /** + * Adds a floating task to the list at the given index + * + * @param toAdd + * @param index + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(FloatingTask toAdd, int index) throws DuplicateFloatingTaskException{ + assert toAdd != null; + assert index>=0; + if (contains(toAdd)) { + throw new DuplicateFloatingTaskException(); + } + internalList.add(index, toAdd); + } + + public void edit(FloatingTask edited, ReadOnlyFloatingTask beforeEdit) throws DuplicateFloatingTaskException, FloatingTaskNotFoundException { + assert edited!=null; + assert beforeEdit!=null; + if (containsWithTags(edited)) { + throw new DuplicateFloatingTaskException(); + } + + if (!contains(beforeEdit)) { + throw new FloatingTaskNotFoundException(); + } + + int indexToReplace = internalList.indexOf(beforeEdit); + internalList.remove(beforeEdit); + internalList.add(indexToReplace, edited); + } + + public void complete(ReadOnlyFloatingTask toComplete) throws FloatingTaskCompletedException, FloatingTaskNotFoundException { + assert toComplete != null; + if (toComplete.getCompleted()) { + throw new FloatingTaskCompletedException(); + } + + if (!contains(toComplete)) { + throw new FloatingTaskNotFoundException(); + } + toComplete.setCompleted(); + updateFloatingTaskList(toComplete); + } + + /** + * Marks the task in the list. + * + * @throws DuplicateFloatingTaskException if the task to add is a duplicate of an existing task in the list. + * @throws FloatingTaskMarkedException if the deadline is already marked. + * @throws FloatingTaskUnmarkedException if the deadline is already unmarked. + */ + public void mark(ReadOnlyFloatingTask taskToMark, boolean marked) + throws FloatingTaskNotFoundException, FloatingTaskMarkedException, FloatingTaskUnmarkedException { + if (taskToMark.isMarked() && marked) { + throw new FloatingTaskMarkedException(); + } else if (!taskToMark.isMarked() && !marked) { + throw new FloatingTaskUnmarkedException(); + } + + if (!contains(taskToMark)) { + throw new FloatingTaskNotFoundException(); + } + taskToMark.setMarked(marked); + updateFloatingTaskList(taskToMark); + } + + private void updateFloatingTaskList(ReadOnlyFloatingTask toComplete) { + int indexToReplace = internalList.indexOf(toComplete); + internalList.remove(toComplete); + internalList.add(indexToReplace, (FloatingTask) toComplete); + } + + /** + * Removes the equivalent task from the list. + * + * @throws FloatingTaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyFloatingTask toRemove) throws FloatingTaskNotFoundException { + assert toRemove != null; + final boolean taskFoundAndDeleted = internalList.remove(toRemove); + if (!taskFoundAndDeleted) { + throw new FloatingTaskNotFoundException(); + } + return taskFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueFloatingTaskList // instanceof handles nulls + && this.internalList.equals( + ((UniqueFloatingTaskList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + +} +``` diff --git a/collated/main/A0153006W.md b/collated/main/A0153006W.md new file mode 100644 index 000000000000..6b3887554323 --- /dev/null +++ b/collated/main/A0153006W.md @@ -0,0 +1,595 @@ +# A0153006W +###### \java\seedu\malitio\logic\commands\ListCommand.java +``` java + */ +public class ListCommand extends Command { + + public static final String COMMAND_WORD = "list"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Lists specified type of task to Malitio\n" + + "Parameters: [events|deadlines|tasks] [DATETIME]\n" + + "Example: " + COMMAND_WORD + " deadlines " + "sunday midnight"; + + public static final String ALL_MESSAGE_SUCCESS = "Listed all tasks"; + public static final String TASK_MESSAGE_SUCCESS = "Listed floating tasks"; + public static final String DEADLINE_MESSAGE_SUCCESS = "Listed deadlines"; + public static final String EVENT_MESSAGE_SUCCESS = "Listed events"; + + private String taskType = ""; + private DateTime timeKeyWord = null; + + public ListCommand() {} + + public ListCommand(String args) throws IllegalValueException { + if (args.matches("(floating )?tasks?.*")) { + this.taskType = "tasks"; + return; + } + else if (args.matches("deadlines?.*")) { + this.taskType = "deadlines"; + args = args.replaceAll("deadlines?\\s*", ""); + } + else if (args.matches("events?.*")) { + this.taskType = "events"; + args = args.replaceAll("events?\\s*", ""); + } + if (!args.isEmpty()) { + timeKeyWord = new DateTime(args); + } + } + + @Override + public CommandResult execute() { + if (taskType.equals("tasks")) { + model.updateFilteredTaskListToShowAll(); + return new CommandResult(TASK_MESSAGE_SUCCESS); + } else if (taskType.equals("deadlines")) { + if (timeKeyWord != null) { + model.updateFilteredDeadlineList(timeKeyWord); + } else { + model.updateFilteredDeadlineListToShowAll(); + } + return new CommandResult(DEADLINE_MESSAGE_SUCCESS); + } else if (taskType.equals("events")) { + if (timeKeyWord != null) { + model.updateFilteredEventList(timeKeyWord); + } else { + model.updateFilteredEventListToShowAll(); + } + return new CommandResult(EVENT_MESSAGE_SUCCESS); + } else { + if (timeKeyWord != null) { + model.updateFilteredDeadlineList(timeKeyWord); + model.updateFilteredEventList(timeKeyWord); + } else { + model.updateFilteredTaskListToShowAll(); + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + } + return new CommandResult(ALL_MESSAGE_SUCCESS); + } + } +} +``` +###### \java\seedu\malitio\logic\commands\MarkCommand.java +``` java + */ +public class MarkCommand extends Command { + + public static final String COMMAND_WORD = "mark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Marks specified task or deadline as priority in Malitio\n" + + "Parameters: INDEX\n" + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_MARK_SUCCESS = "Task has been marked as priority"; + + private final int targetIndex; + private final char taskType; + + public MarkCommand(char taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + if (!(taskType == 'f' || taskType == 'd' || taskType == 'e')) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + if (taskType == 'f') { + model.getFuture().clear(); + return executeMarkFloatingTask(); + } else if (taskType == 'd') { + model.getFuture().clear(); + return executeMarkDeadline(); + } else { + model.getFuture().clear(); + return executeMarkEvent(); + } + } + + private CommandResult executeMarkFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markFloatingTask(taskToMark, true); + } catch (FloatingTaskNotFoundException e) { + assert false : "The target floating task cannot be missing"; + } catch (FloatingTaskMarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (FloatingTaskUnmarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeMarkDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markDeadline(deadlineToMark, true); + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (DeadlineMarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (DeadlineUnmarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeMarkEvent() { + UnmodifiableObservableList lastShownList = model.getFilteredEventList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyEvent eventToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markEvent(eventToMark, true); + } catch (EventNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (EventMarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (EventUnmarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } +} +``` +###### \java\seedu\malitio\logic\commands\UnmarkCommand.java +``` java + */ +public class UnmarkCommand extends Command { + + public static final String COMMAND_WORD = "unmark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Unmarks specified task or deadline as priority in Malitio\n" + + "Parameters: INDEX\n" + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_MARK_SUCCESS = "Task has been unmarked as priority"; + + private final int targetIndex; + private final char taskType; + + public UnmarkCommand(char taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + if (!(taskType == 'f' || taskType == 'd' || taskType == 'e')) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + if (taskType == 'f') { + model.getFuture().clear(); + return executeUnmarkFloatingTask(); + } else if (taskType == 'd') { + model.getFuture().clear(); + return executeUnmarkDeadline(); + } else { + model.getFuture().clear(); + return executeUnmarkEvent(); + } + } + + private CommandResult executeUnmarkFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markFloatingTask(taskToMark, false); + } catch (FloatingTaskNotFoundException e) { + assert false : "The target floating task cannot be missing"; + } catch (FloatingTaskUnmarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (FloatingTaskMarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeUnmarkDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markDeadline(deadlineToMark, false); + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (DeadlineUnmarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (DeadlineMarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + private CommandResult executeUnmarkEvent() { + UnmodifiableObservableList lastShownList = model.getFilteredEventList(); + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyEvent eventToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markEvent(eventToMark, false); + } catch (EventNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (EventUnmarkedException e) { + return new CommandResult(MESSAGE_MARK_SUCCESS); + } catch (EventMarkedException e) { + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } +} +``` +###### \java\seedu\malitio\logic\parser\Parser.java +``` java + */ + private Command prepareAdd(String args){ + final Matcher matcher = TASK_DATA_ARGS_FORMAT.matcher(args.trim()); + boolean hasStart = false; + boolean hasEnd = false; + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + try { + String name = matcher.group("name"); + + String deadline = getDeadlineFromArgs(StringUtil.removeTagsFromString(name)); + if (!deadline.isEmpty()) { + name = name.replaceAll("by " + deadline, ""); + } + + String start = getStartFromArgs(StringUtil.removeTagsFromString(name)); + if (!start.isEmpty()) { + name = name.replaceAll("start " + start, ""); + hasStart = true; + } + + String end = getEndFromArgs(StringUtil.removeTagsFromString(name)); + if (!end.isEmpty()) { + name = name.replaceAll("end " + end, ""); + hasEnd = true; + } + + if (!deadline.isEmpty() && !hasStart && !hasEnd) { + return new AddCommand( + name, + deadline, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (hasStart && hasEnd) { + return new AddCommand( + name, + start, + end, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (hasStart ^ hasEnd) { + return new IncorrectCommand("Expecting start and end times\nExample: start thursday 800 end thursday 900"); + } else if (!deadline.isEmpty() && hasStart || !deadline.isEmpty() && hasEnd) { + return new IncorrectCommand("Expecting either a duedate or start and end time."); + + } + return new AddCommand( + name, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the edit task command. + * + * @param arguments + * @return the prepared command + */ + private Command prepareEdit(String args) { + final Matcher matcher = EDIT_DATA_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + String name = matcher.group("name"); + if (name.equals("") && getTagsFromArgs(matcher.group("tagArguments")).isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + String deadline = getDeadlineFromArgs(name); + if (!deadline.isEmpty()) { + name = name.replaceAll(" by " + deadline, ""); + } + + String start = getStartFromArgs(name); + if (!start.isEmpty()) { + name = name.replaceAll(" start " + start, ""); + } + + String end = getEndFromArgs(name); + if (!end.isEmpty()) { + name = name.replaceAll(" end " + end, ""); + } + + if (taskType == 'd') { + return new EditCommand( + taskType, + taskNum, + name, + deadline, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (taskType == 'e') { + return new EditCommand( + taskType, + taskNum, + name, + start, + end, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } + return new EditCommand( + taskType, + taskNum, + name, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the complete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareComplete(String args) { + final Matcher matcher = COMPLETE_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new CompleteCommand(taskType,taskNum); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the delete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareDelete(String args) { + String index = parseIndex(args); + if(index.isEmpty()) { + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new DeleteCommand(Character.toString(taskType), taskNum); + } + + /** + * Parses arguments in the context of the mark task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareMark(String args) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkCommand.MESSAGE_USAGE)); + } + String index = parseIndex(args); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + return new MarkCommand(taskType, taskNum); + } + + /** + * Parses arguments in the context of the unmark task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareUnmark(String args) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnmarkCommand.MESSAGE_USAGE)); + } + String index = parseIndex(args); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnmarkCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + return new UnmarkCommand(taskType, taskNum); + } + + /** + * Parses arguments in the context of the find task command. + * + * @param args full command args string + * @return the prepared command +``` +###### \java\seedu\malitio\logic\parser\Parser.java +``` java + */ + private Command prepareList(String args) { + if (args.isEmpty()) { + return new ListCommand(); + } + try { + args = args.trim().toLowerCase(); + return new ListCommand(args); + } catch (IllegalValueException ive) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE)); + } + } + + /** + * Returns the specified index as a String in the {@code command} + */ + private String parseIndex(String command) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim()); + if (!matcher.matches()) { + return ""; + } + String index = command.trim().toLowerCase(); + return index; + } + + /** + * Extracts the task's deadline from the command's arguments string. + */ + private static String getDeadlineFromArgs(String args) throws IllegalValueException { + int byIndex = args.lastIndexOf("by"); + String deadline = ""; + if(byIndex > 0 && byIndex < args.length() - 2) { + deadline = args.substring(byIndex + 3); + } + return deadline; + } + + /** + * Extracts the task's event start from the command's arguments string. + */ + private static String getStartFromArgs(String args) throws IllegalValueException { + int startIndex = args.lastIndexOf("start"); + int endIndex = args.lastIndexOf("end"); + if (startIndex > 0 && endIndex > 0) { + return args.substring(startIndex + 6, endIndex - 1); + } else if (startIndex > 0 && endIndex < 0) { + return args.substring(startIndex + 6); + } else { + return ""; + } + } + + /** + * Extracts the task's event end from the command's arguments string. + */ + private static String getEndFromArgs(String args) throws IllegalValueException { + int endIndex = args.lastIndexOf("end"); + if (endIndex > 0) { + return args.substring(endIndex + 4); + } else { + return ""; + } + } + + /** + * Extracts the new task's tags from the add command's tag arguments string. + * Merges duplicate tag strings. +``` +###### \java\seedu\malitio\model\ModelManager.java +``` java + @Override + public void markFloatingTask(ReadOnlyFloatingTask taskToMark, boolean marked) + throws FloatingTaskNotFoundException, FloatingTaskMarkedException, FloatingTaskUnmarkedException { + malitio.markTask(taskToMark, marked); + history.add(new InputMarkHistory(taskToMark, marked)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void markDeadline(ReadOnlyDeadline deadlineToMark, boolean marked) + throws DeadlineNotFoundException, DeadlineMarkedException, DeadlineUnmarkedException { + malitio.markDeadline(deadlineToMark, marked); + history.add(new InputMarkHistory(deadlineToMark, marked)); + updateFilteredDeadlineListToShowAll(); + indicateMalitioChanged(); + } + + @Override + public void markEvent(ReadOnlyEvent eventToMark, boolean marked) + throws EventNotFoundException, EventMarkedException, EventUnmarkedException { + malitio.markEvent(eventToMark, marked); + history.add(new InputMarkHistory(eventToMark, marked)); + updateFilteredEventListToShowAll(); + indicateMalitioChanged(); + } +``` diff --git a/collated/main/a0126633j.md b/collated/main/a0126633j.md new file mode 100644 index 000000000000..721b4dd83f4c --- /dev/null +++ b/collated/main/a0126633j.md @@ -0,0 +1,361 @@ +# a0126633j +###### \java\seedu\malitio\commons\events\storage\DataStorageFileChangedEvent.java +``` java +public class DataStorageFileChangedEvent extends BaseEvent { + + public String dataFilePath; + + public DataStorageFileChangedEvent(String dataFilePath) { + this.dataFilePath = dataFilePath; + } + + @Override + public String toString() { + return "Directory of storage changed to " + dataFilePath; + } + +} +``` +###### \java\seedu\malitio\commons\util\ConfigUtil.java +``` java + public static void changeMalitioSaveDirectory(String dataFilePath) { + Config existingConfig; + + try { + Optional config = readConfig(Config.DEFAULT_CONFIG_FILE); + existingConfig = config.orElse(new Config()); + } catch (DataConversionException e) { + logger.warning("Could not find existing Config file. Created a new Config file."); + existingConfig = new Config(); + } + + existingConfig.setMalitioFilePath(dataFilePath); + try { + saveConfig(existingConfig, Config.DEFAULT_CONFIG_FILE); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + } + +} +``` +###### \java\seedu\malitio\commons\util\FileUtil.java +``` java + public static void deleteFile(String filePath) throws IOException { + Path path = Paths.get(filePath); + Files.deleteIfExists(path); + } + + public static boolean twoFilePathsAreEqual(String filePath1, String filePath2) throws IOException { + try { + if(new File(filePath1).getCanonicalPath().compareTo(new File(filePath2).getCanonicalPath()) == 0) { + return true; + } + } catch (IOException e1) { + throw new IOException("Fail to compare two file paths"); + } + return false; + } +} +``` +###### \java\seedu\malitio\commons\util\StringUtil.java +``` java + public static String removeSlashesAtBeginningOfString(String arg) { + while(arg.charAt(0) == '/') { + arg = arg.substring(1); + } + return arg; + } +} +``` +###### \java\seedu\malitio\logic\commands\DeleteCommand.java +``` java + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the task identified by the index used in the last task listing.\n" + + "Parameters: INDEX \n" + "Example: " + COMMAND_WORD + " D1"; + + public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted %1$s"; + + private static final String[] TYPES_OF_TASKS = {"f","d", "e"}; + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + private final int targetIndex; + private final String taskType; + + public DeleteCommand(String taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + + assert(Arrays.asList(TYPES_OF_TASKS).contains(taskType)); + + int sizeOfList = 0; + + switch (taskType) { + case FLOATING_TASK_KEYWORD: + UnmodifiableObservableList lastShownFloatingTaskList = model.getFilteredFloatingTaskList(); + sizeOfList = lastShownFloatingTaskList.size(); + break; + case DEADLINE_KEYWORD: + UnmodifiableObservableList lastShownDeadlineList = model.getFilteredDeadlineList(); + sizeOfList = lastShownDeadlineList.size(); + break; + case EVENT_KEYWORD: + UnmodifiableObservableList lastShownEventList = model.getFilteredEventList(); + sizeOfList = lastShownEventList.size(); + } + + if (sizeOfList < targetIndex || targetIndex < 1) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + switch (taskType) { + case FLOATING_TASK_KEYWORD: + ReadOnlyFloatingTask taskToDelete = model.getFilteredFloatingTaskList().get(targetIndex - 1); + executeDelete(taskToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + + case DEADLINE_KEYWORD: + ReadOnlyDeadline deadlineToDelete = model.getFilteredDeadlineList().get(targetIndex - 1); + executeDelete(deadlineToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, deadlineToDelete)); + + default: + assert(taskType.equals(EVENT_KEYWORD)); + ReadOnlyEvent eventToDelete = model.getFilteredEventList().get(targetIndex - 1); + executeDelete(eventToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, eventToDelete)); + } + } + + /** + * overloading executeDelete function for different tasks + * + */ + private void executeDelete(ReadOnlyFloatingTask taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target floating task cannot be missing"; + } + } + + private void executeDelete(ReadOnlyDeadline taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } + } + + private void executeDelete(ReadOnlyEvent taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (EventNotFoundException pnfe) { + assert false : "The target event cannot be missing"; + } + } +} +``` +###### \java\seedu\malitio\logic\commands\FindCommand.java +``` java + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds [specified] tasks whose names contain any of " + + "the specified keywords and displays them as a list with index numbers.\n" + + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " [f/d/e] adjust bring chill"; + + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + private final Set keywords; + private final String typeOfTask; + + public FindCommand(String type, Set keywords) { + this.keywords = keywords; + this.typeOfTask = type; + } + + @Override + public CommandResult execute() { + + switch (typeOfTask) { + case FLOATING_TASK_KEYWORD: + model.updateFilteredTaskList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredFloatingTaskList().size())); + case DEADLINE_KEYWORD: + model.updateFilteredDeadlineList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredDeadlineList().size())); + case EVENT_KEYWORD: + model.updateFilteredEventList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredEventList().size())); + + default: //find in all lists + model.updateFilteredTaskList(keywords); + model.updateFilteredDeadlineList(keywords); + model.updateFilteredEventList(keywords); + return new CommandResult(getMessageForTaskListShownSummary( + model.getFilteredFloatingTaskList().size() + + model.getFilteredDeadlineList().size() + + model.getFilteredEventList().size())); + } + } + +} +``` +###### \java\seedu\malitio\logic\commands\SaveCommand.java +``` java +/** + * Allows the user to change the directory of save file. Old file in old directory will be deleted. + * The new directory will be remembered next time the App starts. + */ +public class SaveCommand extends Command { + + private static final Logger logger = LogsCenter.getLogger(SaveCommand.class); + + public static final String COMMAND_WORD = "save"; + + public static final String MESSAGE_DIRECTORY_EXAMPLE = "C://Users/User PC/Downloads/"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a task to Malitio.\n" + + "Parameters: File Directory\n" + + "Example: " + COMMAND_WORD + + " " + MESSAGE_DIRECTORY_EXAMPLE; + + public static final String MESSAGE_SAVE_SUCCESSFUL = "Malitio data will be saved in %s from now onwards."; + + public static final String MESSAGE_INVALID_DIRECTORY = "The directory is invalid!\nExample: "; + + public static final char FILE_PATH_IDENTIFIER = '/'; + + private final String dataFilePath; + + /** + * Initialises dataFilePath to the input if the input ends with '/', else set dataFilePath to null + * + */ + public SaveCommand(String dataFilePath) { + if(dataFilePath.charAt(dataFilePath.length() - 1) == FILE_PATH_IDENTIFIER) { + this.dataFilePath = StringUtil.removeSlashesAtBeginningOfString(dataFilePath.trim()) + Config.DEFAULT_FILE_NAME; + } else { + this.dataFilePath = null; + } + } + + @Override + public CommandResult execute() { + if(!isValidFilePath()) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(MESSAGE_INVALID_DIRECTORY + MESSAGE_DIRECTORY_EXAMPLE); + } + EventsCenter.getInstance().post(new DataStorageFileChangedEvent(dataFilePath)); + ConfigUtil.changeMalitioSaveDirectory(dataFilePath); + + return new CommandResult(String.format(MESSAGE_SAVE_SUCCESSFUL, dataFilePath)); + } + + /** + * Checks if the input by user is a valid file path + */ + private boolean isValidFilePath() { + if(dataFilePath == null || dataFilePath.contains("\\")) { + return false; + } + + File file = new File(dataFilePath); + try { + if(!FileUtil.createFile(file)) { + logger.warning("File already exists"); + } + return true; + } catch (IOException e) { + return false; + } + } +} +``` +###### \java\seedu\malitio\model\task\DateTime.java +``` java +public class DateTime { + public static final String MESSAGE_DATETIME_CONSTRAINTS = "Unrecognised date and time!"; + + private Date date; + + private static DateFormat outputFormatter = new SimpleDateFormat("MM-dd-yyyy HH:mm"); + + /** + * Converts the string that contains date information into Date + * + * @throws IllegalValueException if the format of date is unrecognised + */ + public DateTime(String date) throws IllegalValueException { + + this.date = DateParser.parse(date); + if (this.date == null) { + throw new IllegalValueException(MESSAGE_DATETIME_CONSTRAINTS); + } + } + + public String toString() { + String newDateString = outputFormatter.format(date); + return newDateString; + } + + public int compareTo(DateTime dateTime) { + return date.compareTo(dateTime.getDate()); + } + + public Date getDate() { + return date; + } +} +``` +###### \java\seedu\malitio\storage\StorageManager.java +``` java + @Subscribe + public void handleDataStorageFileChangedEvent(DataStorageFileChangedEvent event) throws DataConversionException, IOException { + String oldDataFilePath = malitioStorage.getMalitioFilePath(); + malitioStorage = new XmlMalitioStorage(event.dataFilePath); + + if(FileUtil.twoFilePathsAreEqual(oldDataFilePath, this.malitioStorage.getMalitioFilePath())) { + return; + } + + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Data storage file path changed, updating..")); + + try { + saveMalitio(readMalitio(oldDataFilePath).get(), this.malitioStorage.getMalitioFilePath()); + } catch (IOException e) { + raise(new DataSavingExceptionEvent(e)); + } + + try { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Old data file is being deleted.")); + FileUtil.deleteFile(oldDataFilePath); + } catch (IOException e) { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Failed to delete old data file.")); + } + } +} +``` +###### \java\seedu\malitio\ui\StatusBarFooter.java +``` java + @Subscribe + public void handleDataStorageFileChangedEvent(DataStorageFileChangedEvent event) { + setSaveLocation(event.dataFilePath); + } +} +``` diff --git a/collated/test/A0122460W.md b/collated/test/A0122460W.md new file mode 100644 index 000000000000..2b6e091ff14a --- /dev/null +++ b/collated/test/A0122460W.md @@ -0,0 +1,50 @@ +# A0122460W +###### \java\guitests\CompleteCommandTest.java +``` java +public class CompleteCommandTest extends MalitioGuiTest { + + @Test + public void completeFloatingtask() { + + // complete floating task + TestFloatingTask[] currentList = td.getTypicalFloatingTasks(); + TestFloatingTask toComplete = td.floatingTask1; + commandBox.runCommand("complete f1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_TASK_SUCCESS)); + + // cannot complete a completed floating task + commandBox.runCommand("complete f1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_TASK)); + + // complete error command + commandBox.runCommand("complete"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + + commandBox.runCommand("complete asdf"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + + // complete with an invalid index + commandBox.runCommand("complete f200"); + assertResultMessage(String.format(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX)); + } + + @Test + public void completeDeadline() { + + // complete deadline + TestDeadline[] currentList = td.getTypicalDeadlines(); + TestDeadline toComplete = td.deadline1; + commandBox.runCommand("complete d1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_DEADLINE_SUCCESS)); + + // cannot complete a completed deadline + commandBox.runCommand("complete d1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_DEADLINE)); + + // complete with an invalid index + commandBox.runCommand("complete d200"); + assertResultMessage(String.format(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX)); + } + +} +``` diff --git a/collated/test/A0129595N.md b/collated/test/A0129595N.md new file mode 100644 index 000000000000..68d145523f1f --- /dev/null +++ b/collated/test/A0129595N.md @@ -0,0 +1,170 @@ +# A0129595N +###### \java\guitests\EditCommandTest.java +``` java +public class EditCommandTest extends MalitioGuiTest { + + @Test + public void editFloatingtask() { + + // Edit name of floating task + TestFloatingTask[] currentList = td.getTypicalFloatingTasks(); + TestFloatingTask toEdit = td.floatingTask1; + TestFloatingTask edited = td.editedFloatingTask1; + commandBox.runCommand("edit f1 how are you"); + assertEditSuccess(edited, 0, currentList); + + // Edit tags of floating task + toEdit = td.floatingTask2; + edited = td.editedFloatingTask2; + commandBox.runCommand("edit f2 t/omg"); + assertEditSuccess(edited, 1, currentList); + + // Edit both name and tags of floatingtask + toEdit = td.floatingTask3; + edited = td.editedFloatingTask3; + commandBox.runCommand("edit f3 Tell Nobody t/heello"); + assertEditSuccess(edited, 2, currentList); + + // Edit with an invalid index + commandBox.runCommand("edit f200"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + + // Edit a task to one which already exists + commandBox.runCommand("edit f1 Tell Nobody t/heello"); + assertResultMessage(EditCommand.MESSAGE_DUPLICATE_TASK); + } + + @Test + public void editDeadline() { + + // Edit name (only) of deadline + TestDeadline[] currentList = td.getTypicalDeadlines(); + TestDeadline toEdit = td.deadline1; + TestDeadline edited = td.editedDeadline1; + commandBox.runCommand("edit d1 Cut more hair "); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); // revert back to original state + + // Edit due date (only) of dateline + toEdit = td.deadline2; + edited = td.editedDeadline2; + commandBox.runCommand("edit d2 by 22 dec 12am"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit tag (only) of deadline + toEdit = td.deadline3; + edited = td.editedDeadline3; + commandBox.runCommand("edit d3 t/Pineapple t/Pen"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit name, duedate and tags of deadline + toEdit = td.deadline4; + edited = td.editedDeadline4; + commandBox.runCommand("edit d4 I want to sleep by 25 oct 11pm t/damntired"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit with an invalid index + commandBox.runCommand("edit d200"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + + // Edit a deadline to one which already exists + commandBox.runCommand("edit d1 Practice singing by 12-25 12am t/Christmas t/Carols"); + assertResultMessage(EditCommand.MESSAGE_DUPLICATE_DEADLINE); + } + + @Test + public void editEvent() { + + // Edit name (only) of event + TestEvent[] currentList = td.getTypicalEvents(); + TestEvent toEdit = td.event1; + TestEvent edited = td.editedEvent1; + commandBox.runCommand("edit e1 Eat with dad"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); // revert back to original state + + // Edit start (only) of event + toEdit = td.event2; + edited = td.editedEvent2; + commandBox.runCommand("edit e2 start 22 feb 2017 1pm"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit end (only) of event + toEdit = td.event3; + edited = td.editedEvent3; + commandBox.runCommand("edit e3 end 30 march 2017 9pm"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit tag (only) of event + toEdit = td.event4; + edited = td.editedEvent4; + commandBox.runCommand("edit e4 t/fun t/yahoo"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit name, start, end and tags of deadline + toEdit = td.event5; + edited = td.editedEvent5; + commandBox.runCommand("edit e5 Outing start 02-14-2017 10am end 02-14-2017 8pm t/dressup"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit with an invalid index + commandBox.runCommand("edit e200"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + + // Edit an event to one which already exists + commandBox.runCommand("edit e1 New year party start 12-31-2017 12am end 12-31-2017 11.59pm t/null"); + assertResultMessage(EditCommand.MESSAGE_DUPLICATE_EVENT); + + // Edit an event's start date later than end date + commandBox.runCommand("edit e5 start 12-26-2017"); + assertResultMessage(EditCommand.MESSAGE_INVALID_EVENT); + + } + + /** + * @param edited + * @param index + * @param currentList + */ + private void assertEditSuccess(TestFloatingTask edited, int index, TestFloatingTask... currentList) { + currentList = TestUtil.replaceTaskFromList(currentList, edited, index); + assertTrue(floatingTaskListPanel.isListMatching(currentList)); + } + + /** + * @param edited + * @param toEdit + * @param currentList + * @return updated TestDeadline array. + */ + private void assertEditSuccess(TestDeadline edited, TestDeadline toEdit, TestDeadline... currentList) { + currentList = TestUtil.removeTasksFromList(currentList, toEdit); + currentList = TestUtil.addTasksToList(currentList, edited); + assertTrue(deadlineListPanel.isListMatching(currentList)); + } + + /** + * @param edited + * @param toEdit + * @param currentList + * @return updated TestDeadline array. + */ + private void assertEditSuccess(TestEvent edited, TestEvent toEdit, TestEvent... currentList) { + currentList = TestUtil.removeTasksFromList(currentList, toEdit); + currentList = TestUtil.addTasksToList(currentList, edited); + try { + assertTrue(eventListPanel.isListMatching(currentList)); + } catch (IllegalArgumentException | IllegalValueException e) { + assert false : "Not possible"; + } + } + +} +``` diff --git a/collated/test/A0153006W.md b/collated/test/A0153006W.md new file mode 100644 index 000000000000..21f027b49bfe --- /dev/null +++ b/collated/test/A0153006W.md @@ -0,0 +1,118 @@ +# A0153006W +###### \java\guitests\ListCommandTest.java +``` java + @Test + public void list() { + + //verify list shows all items after panels are empty + commandBox.runCommand("find x"); + assertListCommandSuccess(); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + assertTrue(deadlineListPanel.isListMatching(td.getTypicalDeadlines())); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + e.printStackTrace(); + } + } + + @Test + public void listTasks() { + + //verify list tasks only updates the tasks panel + commandBox.runCommand("find x"); + assertListCommandSuccess("floating tasks"); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + assertDeadlineListSize(0); + assertEventListSize(0); + + //verify list tasks [DATETIME] updates to all floating tasks + commandBox.runCommand("find x"); + assertListCommandSuccess("floating tasks", "10-31 2am"); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + } + + @Test + public void listDeadlines() { + + //verify list deadlines only updates the deadlines panel + commandBox.runCommand("find x"); + assertListCommandSuccess("deadlines"); + assertTrue(deadlineListPanel.isListMatching(td.getTypicalDeadlines())); + assertFloatingTaskListSize(0); + assertEventListSize(0); + + //verify list deadlines [DATETIME] updates to deadlines with due dates on or after [DATETIME] + assertListCommandSuccess(); + assertListCommandSuccess("deadlines", "12-27 midnight"); + assertTrue(deadlineListPanel.isListMatching(td.deadline5)); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + } + + @Test + public void listEvents() { + + //verify list events only updates the events panel + commandBox.runCommand("find x"); + assertListCommandSuccess("events"); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + assertFloatingTaskListSize(0); + assertDeadlineListSize(0); + + //verify list events [DATETIME] updates to events that start on or after [DATETIME] + assertListCommandSuccess(); + assertListCommandSuccess("events", "12-31-17 0000"); + try { + assertTrue(eventListPanel.isListMatching(td.event6)); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + assertTrue(deadlineListPanel.isListMatching(td.getTypicalDeadlines())); + } + + @Test + public void listDateTime() { + + //verify list [DATETIME] updates both deadlines and events + commandBox.runCommand("find x"); + assertListCommandSuccess("", "12-27"); + assertFloatingTaskListSize(0); + assertTrue(deadlineListPanel.isListMatching(td.deadline5)); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + } + + private void assertListCommandSuccess() { + commandBox.runCommand("list"); + assertResultMessage("Listed all tasks"); + } + + private void assertListCommandSuccess(String taskType) { + commandBox.runCommand("list " + taskType); + assertResultMessage("Listed " + taskType); + } + + private void assertListCommandSuccess(String taskType, String dateTime) { + commandBox.runCommand("list " + taskType + " " + dateTime); + if (taskType.isEmpty()) { + assertResultMessage("Listed all tasks"); + } + else { + assertResultMessage("Listed " + taskType); + } + } +} +``` diff --git a/collated/test/a0126633j.md b/collated/test/a0126633j.md new file mode 100644 index 000000000000..8bb1a7a8e5fd --- /dev/null +++ b/collated/test/a0126633j.md @@ -0,0 +1,156 @@ +# a0126633j +###### \java\guitests\DeleteCommandTest.java +``` java +public class DeleteCommandTest extends MalitioGuiTest { + + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + @Test + public void delete() { + + //Populate test tasks + TestFloatingTask[] floatingTaskList = td.getTypicalFloatingTasks(); //5 floating tasks + TestDeadline[] deadlineList = td.getTypicalDeadlines(); // 2 deadlines + TestEvent[] eventList = td.getTypicalEvents(); // 4 events + + //invalid index argument + commandBox.runCommand("delete " + FLOATING_TASK_KEYWORD + floatingTaskList.length + 1); // boundary + assertResultMessage("The task index provided is invalid"); + commandBox.runCommand("delete " + EVENT_KEYWORD + 0); // boundary + assertResultMessage("The task index provided is invalid"); + commandBox.runCommand("delete " + "g1"); // invalid task type + assertResultMessage("The task index provided is invalid"); + + // to save time, work on each list because each list is identical + //delete first in floating task + int targetIndex = 1; + assertDeleteSuccess(targetIndex, floatingTaskList); + + //delete the last in deadline + targetIndex = deadlineList.length; + assertDeleteSuccess(targetIndex, deadlineList); + + //delete from the middle of event list + targetIndex = eventList.length/2; + assertDeleteSuccess(targetIndex, eventList); + + + } + + /** + * Runs the delete command to delete the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to delete the first task in the list, 1 should be given as the target index. + * @param floatingTaskList A copy of the current list of tasks (before deletion). + */ + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestFloatingTask[] floatingTaskList) { + TestFloatingTask taskToDelete = floatingTaskList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestFloatingTask[] expectedRemainder = TestUtil.removeTasksFromList(floatingTaskList, targetIndexOneIndexed); + + commandBox.runCommand("delete " + FLOATING_TASK_KEYWORD + targetIndexOneIndexed); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(floatingTaskListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestDeadline[] deadlineList) { + TestDeadline taskToDelete = deadlineList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestDeadline[] expectedRemainder = TestUtil.removeTasksFromList(deadlineList, taskToDelete); + + commandBox.runCommand("delete " + DEADLINE_KEYWORD + targetIndexOneIndexed); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(deadlineListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestEvent[] eventList) { + TestEvent taskToDelete = eventList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestEvent[] expectedRemainder = TestUtil.removeTasksFromList(eventList, taskToDelete); + + commandBox.runCommand("delete " + EVENT_KEYWORD + targetIndexOneIndexed); + + //confirm the list now contains all previous tasks except the deleted task + try { + assertTrue(eventListPanel.isListMatching(expectedRemainder)); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalValueException e) { + e.printStackTrace(); + } + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + +} +``` +###### \java\guitests\FindCommandTest.java +``` java +public class FindCommandTest extends MalitioGuiTest { + + @Test + public void find_nonEmptyList() throws IllegalArgumentException, IllegalValueException { + + assertFindEventResult("find with", td.event1, td.event2); //multiple results + assertFindEventResult("find hello"); //no result + + //find after deleting one result + commandBox.runCommand("list"); + commandBox.runCommand("delete f1"); + assertFindFloatingTaskResult("find bring",td.floatingTask2); + } + + @Test + public void find_emptyList() throws IllegalArgumentException, IllegalValueException { + commandBox.runCommand("clear"); + assertFindFloatingTaskResult("find eat"); //no results + assertFindDeadlineResult("find eat"); + assertFindEventResult("find eat"); + } + + @Test + public void find_invalidCommand_fail() { + commandBox.runCommand("finddonothing"); + assertResultMessage(Messages.MESSAGE_UNKNOWN_COMMAND); + } + + @Test + public void find_specificTasks() throws IllegalArgumentException, IllegalValueException { + assertFindDeadlineResult("find d SOME", td.deadline2); + assertFindFloatingTaskResult("find f tell", td.floatingTask3); + + commandBox.runCommand("find e"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); // recognise as finding in event but no keywords + } + + private void assertFindFloatingTaskResult(String command, TestFloatingTask... expectedHits ) { + commandBox.runCommand(command); + assertFloatingTaskListSize(expectedHits.length); + assertResultMessage(expectedHits.length + " tasks found!"); + + assertTrue(floatingTaskListPanel.isListMatching(expectedHits)); + } + private void assertFindDeadlineResult(String command, TestDeadline... expectedHits ) { + commandBox.runCommand(command); + assertDeadlineListSize(expectedHits.length); + assertResultMessage(expectedHits.length + " tasks found!"); + + assertTrue(deadlineListPanel.isListMatching(expectedHits)); + } + private void assertFindEventResult(String command, TestEvent... expectedHits ) throws IllegalArgumentException, IllegalValueException { + commandBox.runCommand(command); + assertEventListSize(expectedHits.length); + assertResultMessage(expectedHits.length + " tasks found!"); + + assertTrue(eventListPanel.isListMatching(expectedHits)); + } +} +``` diff --git a/config.json b/config.json new file mode 100644 index 000000000000..1c55516a885d --- /dev/null +++ b/config.json @@ -0,0 +1,7 @@ +{ + "appTitle" : "Malitio", + "logLevel" : "INFO", + "userPrefsFilePath" : "preferences.json", + "malitioFilePath" : "data/malitio.xml", + "malitioName" : "Malitio" +} \ No newline at end of file diff --git a/config/checkstyle/checkstyle-noframes-sorted.xsl b/config/checkstyle/checkstyle-noframes-sorted.xsl index 9c0ac3054165..441fd41839b4 100644 --- a/config/checkstyle/checkstyle-noframes-sorted.xsl +++ b/config/checkstyle/checkstyle-noframes-sorted.xsl @@ -1,144 +1,159 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -

CheckStyle Audit

Designed for use with CheckStyle and Ant.
-
- - - -
- - - -
- - - - -
- - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

CheckStyle Audit

+
+ Designed for use with + CheckStyle + and + Ant + . +
+
+ + + +
+ + + +
+ + + + +
+ + + + +

Files

- - - - - - - - +
NameErrors
+ + + + + + + - - - + + +
NameErrors
+ + + + + +
@@ -146,50 +161,64 @@ - -

File

- - - - - - - - - - - - - - -
Error DescriptionLine
- Back to top + +

+ File + +

+ + + + + + + + + + + + + + +
Error DescriptionLine
+ + + +
+ Back to top

Summary

- - - - - - - - - - - - + + +
FilesErrors
+ + + + + + + + +
FilesErrors
+ + + +
- - + + a b - +
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 3bab4e05bbae..034a7f591828 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -3,324 +3,253 @@ "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/findbugs/excludeFilter.xml b/config/findbugs/excludeFilter.xml index 03c15ae4cc81..c1aeab75429c 100644 --- a/config/findbugs/excludeFilter.xml +++ b/config/findbugs/excludeFilter.xml @@ -1,12 +1,12 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/copyright.txt b/copyright.txt index 93aa2a39ce25..95ee83798f9a 100644 --- a/copyright.txt +++ b/copyright.txt @@ -7,3 +7,5 @@ Copyright by Susumu Yoshida - http://www.mcdodesign.com/ Copyright by Jan Jan Kovařík - http://glyphicons.com/ - calendar.png - edit.png + +Copyright (c) 2010 Joseph Stelmach \ No newline at end of file diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 33df65bea583..2db04d954b2f 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,49 +4,64 @@ We are a team based in the [School of Computing, National University of Singapor ## Project Team -#### [Damith C. Rajapakse](http://www.comp.nus.edu.sg/~damithch)
-
-**Role**: Project Advisor +####Annabel Eng Jing Wen [@annabeleng](http://github.com/annabeleng)
+
+**Role**: Team Leader
+* Component in charge of: [Model](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/DeveloperGuide.md#model-component)
+* Aspects/tools in charge of: Documentation
+* Features implemented:
+ * [Edit Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#edit-a-task--edit)
+ * [Undo Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#undo-the-most-recent-action-undo)
+ * [Redo Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#redo-the-most-recent-action-redo)
+* Code written: [[functional code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/main/A0129595N.md) [[test code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/test/A0129595N.md) [[docs]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/docs/A0129595N.md)
+* Other major contributions:
+ * Did the initial refactoring from AddressBook to Malitio (code only/ testing done by Desmond) [[#3]](https://github.com/CS2103AUG2016-* * T13-C3/main/pull/3)
+ * Created the functional model/structure for Malitio [[#20]](https://github.com/CS2103AUG2016-T13-C3/main/pull/20) ----- -#### [Joshua Lee](http://github.com/lejolly) -
+#### [Nathan Kwon](https://github.com/kwonn) +
Role: Developer
-Responsibilities: UI +* Component in charge of: [Logic](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/DeveloperGuide.md#logic-component)
+* Aspects/tools in charge of: Integration, GitHub
+* Features implemented:
+ * [List Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#listing-tasks-list)
+ * [Mark Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#marking-as-priority--mark)
+ * [Unmark Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#marking-as-priority--unmark)
+* Code written: [[functional code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/main/A0153006W.md) [[test code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/test/A0153006W.md) [[docs]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/docs/A0153006W.md) ----- -#### [Leow Yijin](http://github.com/yijinl) -
+#### [Desmond Khoo](http://github.com/DesmondKhoo) +
Role: Developer
-Responsibilities: Data - +* Component in charge of: [Storage](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/DeveloperGuide.md#storage-component)
+* Aspects/tools in charge of: Code Testing
+* Features implemented:
+ * [Save Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#specifying-location-of-local-data-file-save)
+ * [Find Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#finding-all-deadlinesfloating-tasksevents-containing-any-keyword-in-their-names-and-tags-find)
+ * [Delete Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#deleting-a-task--delete)
+* Code written: [[functional code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/main/a0126633j.md) [[test code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/test/a0126633j.md) [[docs]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/docs/a0126633j.md)
+* Other major contributions:
+ * Implemented natty. + * Did the initial refactoring from AddressBook to Malitio for test cases. + ----- -#### [Martin Choo](http://github.com/m133225) -
+#### [Ng Huan Ran](https://github.com/shusiner) +
Role: Developer
-Responsibilities: Dev Ops +* Component in charge of: [UI](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/DeveloperGuide.md#ui-component)
+* Aspects/tools in charge of: Code Quality
+* Features implemented:
+ * [Complete Command](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md#edit-a-task--complete)
+* Code written: [[functional code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/main/A0122460W.md) [[test code]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/test/A0122460W.md) [[docs]](https://github.com/CS2103AUG2016-T13-C3/main/blob/master/collated/docs/A0122460W.md)
+* Other major contributions:
+ * Set the base structure to Malitio ----- -#### [Thien Nguyen](https://github.com/ndt93) - Role: Developer
- Responsibilities: Threading - - ----- - -#### [You Liang](http://github.com/yl-coder) -
- Role: Developer
- Responsibilities: UI - - ----- - # Contributors We welcome contributions. See [Contact Us](ContactUs.md) page for more info. - -* [Akshay Narayan](https://github.com/se-edu/addressbook-level4/pulls?q=is%3Apr+author%3Aokkhoy) -* [Sam Yong](https://github.com/se-edu/addressbook-level4/pulls?q=is%3Apr+author%3Amauris) \ No newline at end of file diff --git a/docs/ContactUs.md b/docs/ContactUs.md index 866d0de3fddc..efd5541c4042 100644 --- a/docs/ContactUs.md +++ b/docs/ContactUs.md @@ -1,6 +1,6 @@ # Contact Us -* **Bug reports, Suggestions** : Post in our [issue tracker](https://github.com/se-edu/addressbook-level4/issues) +* **Bug reports, Suggestions** : Post in our [issue tracker](https://github.com/se-edu/malitio-level4/issues) if you noticed bugs or have suggestions on how to improve. * **Contributing** : We welcome pull requests. Follow the process described [here](https://github.com/oss-generic/process) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 690b6d386627..d95783a752dc 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -52,7 +52,6 @@ **Problem: Eclipse reports some required libraries missing** * Reason: Required libraries may not have been downloaded during the project import. * Solution: [Run tests using Gardle](UsingGradle.md) once (to refresh the libraries). - ## Design @@ -91,7 +90,7 @@ command `delete 3`. ->Note how the `Model` simply raises a `AddressBookChangedEvent` when the Address Book data are changed, +>Note how the `Model` simply raises a `malitioChangedEvent` when the malitio data are changed, instead of asking the `Storage` to save the updates to the hard disk. The diagram below shows how the `EventsCenter` reacts to that event, which eventually results in the updates @@ -110,8 +109,8 @@ The sections below give more details of each component. **API** : [`Ui.java`](../src/main/java/seedu/address/ui/Ui.java) -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, -`StatusBarFooter`, `BrowserPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `(Task)ListPanel`, +`StatusBarFooter`, etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class and they can be loaded using the `UiPartLoader`. The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files @@ -124,6 +123,7 @@ The `UI` component, * Binds itself to some data in the `Model` so that the UI can auto-update when data in the `Model` change. * Responds to events raised from various parts of the App and updates the UI accordingly. + ### Logic component
@@ -132,13 +132,14 @@ The `UI` component, 1. `Logic` uses the `Parser` class to parse the user command. 2. This results in a `Command` object which is executed by the `LogicManager`. -3. The command execution can affect the `Model` (e.g. adding a person) and/or raise events. +3. The command execution can affect the `Model` (e.g. adding a task) and/or raise events. 4. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. Given below is the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` API call.

+ ### Model component
@@ -147,9 +148,11 @@ Given below is the Sequence Diagram for interactions within the `Logic` componen The `Model`, * stores a `UserPref` object that represents the user's preferences. -* stores the Address Book data. -* exposes a `UnmodifiableObservableList` that can be 'observed' e.g. the UI can be bound to this list - so that the UI automatically updates when the data in the list change. +* stores the malitio data. +* stores the history and future of data-changing commands in stacks of InputHistory. +* exposes a `UnmodifiableObservableList`, `UnmodifiableObservableList`, `UnmodifiableObservableList` that can be 'observed' e.g. the UI can be bound to this list + so that the UI automatically updates when the data in any of the list change. +* exposes the two stacks of InputHistory (history and future) for access by UndoCommand and RedoCommand. * does not depend on any of the other three components. ### Storage component @@ -160,11 +163,11 @@ The `Model`, The `Storage` component, * can save `UserPref` objects in json format and read it back. -* can save the Address Book data in xml format and read it back. +* can save the malitio data in xml format and read it back. ### Common classes -Classes used by multiple components are in the `seedu.addressbook.commons` package. +Classes used by multiple components are in the `seedu.malitio.commons` package. ## Implementation @@ -258,7 +261,7 @@ Here are the steps to create a new release. ### Managing Dependencies -A project often depends on third-party libraries. For example, Address Book depends on the +A project often depends on third-party libraries. For example, malitio depends on the [Jackson library](http://wiki.fasterxml.com/JacksonHome) for XML parsing. Managing these _dependencies_ can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
@@ -273,45 +276,60 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (un Priority | As a ... | I want to ... | So that I can... -------- | :-------- | :--------- | :----------- `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App -`* * *` | user | add a new person | -`* * *` | user | delete a person | remove entries that I no longer need -`* * *` | user | find a person by name | locate details of persons without having to go through the entire list -`* *` | user | hide [private contact details](#private-contact-detail) by default | minimize chance of someone else seeing them by accident -`*` | user with many persons in the address book | sort persons by name | locate a person easily +`* * *` | new user | view more information about a particular command | learn how to use various commands +`* * *` | user | add a new to-do | +`* * *` | user | add a new event | +`* * *` | user | add a new deadline | +`* * *` | user | delete a floating task | remove an entry that I no longer need or have completed +`* * *` | user | delete an event | remove an event that has passed or has been cancelled +`* * *` | user | delete a deadline | remove a deadline that has passed or been removed +`* * *` | user | complete floating tasks or deadlines | complete floating tasks and deadlines to remind users that it is completed +`* * *` | user | find a(n) event/deadline/floating task by name | locate details of the event/deadline/task without having to go through the entire list +`* * *` | user | edit a(n) event/deadline/floating task | update it or correct any errors +`* * *` | user | set a(n) event/deadlines/floating task as a priority | know which one should be completed first +`* * *` | user | view all tasks | plan ahead depending on availablity +`* * *` | user | view all tasks on specified day(s) | plan ahead +`* * *` | user | undo my last action | rectify any mistakes I made +`* *` | user | redo my last undo action | rectify the undo in case i changed my mind -{More to be added} ## Appendix B : Use Cases -(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise) +(For all use cases below, the **System** is `Malitio` and the **Actor** is the `User`, unless specified otherwise) -#### Use case: Delete person +#### Use case: Delete a floating task **MSS** -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person
+1. User requests to delete a specific floating task in the floating task list +2. Malitio deletes the floating task
Use case ends. **Extensions** -2a. The list is empty +1a. The given index is invalid -> Use case ends +> 1a1. Malitio shows an error message
+ Use case restarts at step 1 -3a. The given index is invalid +#### Use case: Edit a floating task -> 3a1. AddressBook shows an error message
- Use case resumes at step 2 +**MSS** -{More to be added} +1. User requests to edit a specific floating task by its index and input changes +2. Malitio implement the specified edit and reflect the change to user
+Use case ends. + +**Extensions** +1a. The given index is invalid + +> 1a1. Malitio shows an error message
+ Use case restarts at step 1 ## Appendix C : Non Functional Requirements 1. Should work on any [mainstream OS](#mainstream-os) as long as it has Java `1.8.0_60` or higher installed. -2. Should be able to hold up to 1000 persons. +2. Should be able to hold up to 1000 floating tasks, events and deadlines combined. 3. Should come with automated unit tests and open source code. 4. Should favor DOS style commands over Unix-style commands. @@ -323,11 +341,18 @@ Use case ends. > Windows, Linux, Unix, OS-X -##### Private contact detail +##### Floating task -> A contact detail that is not meant to be shared with others +> A task that has no deadline ## Appendix E : Product Survey -{TODO: Add a summary of competing products} +**Desktop Reminder**
+Desktop Reminder is a desktop application and can be run in offline mode. It has an alert system which will ring at a specified time (determined by user) to alert the user of upcoming tasks. However, the drawback of this application is that it does not minimize to the system tray when user clicked on the 'X' button but instead, gets minimized as a window which will hover on top of the taskbar. + +**Google Calendar and Google Task**
+Google Calender displays the event and on the right side, Google Task shows the tasks which needs completion. This view enables user to see what task they have on which days easily. However, a drawback is that google task is rather simple and does not have a lot of features. + +**Remember The Milk**
+Remember The Milk (RTM) allows users to categorize task which is useful if users want to group related task together. However, a drawback of RTM is that it does not allow users to input specific reminders before the events (e.g. 10minutes before, 1 day before, etc) but only have a general reminder which will be through email to the task. Since there is a mobile app for this, the inability to generate mobile reminders (e.g. alarm or notification) is a potential hindrance especially to users who do not check their emails often. diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 5ee57072a8d8..b2180e20eb50 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -29,7 +29,7 @@ facilitate communication between event creators and event consumers. ## Use API Design `[LO-ApiDesign]` -Note how components of AddressBook have well-defined APIs. For example, the API of the `Logic` component +Note how components of malitio have well-defined APIs. For example, the API of the `Logic` component is given in the [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java)
@@ -41,7 +41,7 @@ is given in the [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java) ## Use Assertions `[LO-Assertions]` -Note how the AddressBook app uses Java `assert`s to verify assumptions. +Note how the malitio app uses Java `assert`s to verify assumptions. **Resources** * [Programming With Assertions](http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html) - a @@ -52,13 +52,13 @@ Note how the AddressBook app uses Java `assert`s to verify assumptions. * Make sure assertions are enabled in Eclipse by forcing an assertion failure (e.g. add `assert false;` somewhere in the code and run the code to ensure the runtime reports an assertion failure). - * Add more assertions to AddressBook as you see fit. + * Add more assertions to malitio as you see fit. ------------------------------------------------------------------------------------------------------ ## Use Logging `[LO-Logging]` -Note [how the AddressBook app uses Java's `java.util.log` package to do logging](DeveloperGuide.md#logging). +Note [how the malitio app uses Java's `java.util.log` package to do logging](DeveloperGuide.md#logging). **Resources** * Tutorials @@ -71,17 +71,17 @@ Note [how the AddressBook app uses Java's `java.util.log` package to do logging] * [Base 22 Java Logging Standards and Guidelines](https://wiki.base22.com/display/btg/Java+Logging+Standards+and+Guidelines) #### Exercise: Add more logging - Add more logging to AddressBook as you see fit. + Add more logging to malitio as you see fit. ------------------------------------------------------------------------------------------------------ ## Use Defensive Coding `[LO-DefensiveCoding]` - Note how AddressBook uses the `ReadOnly*` interfaces to prevent objects being modified by clients who are not + Note how malitio uses the `ReadOnly*` interfaces to prevent objects being modified by clients who are not supposed to modify them. #### Exercise: identify more places for defensive coding - Analyze the AddressBook code/design to identify, + Analyze the malitio code/design to identify, * where defensive coding is used * where the code can be more defensive @@ -89,7 +89,7 @@ Note [how the AddressBook app uses Java's `java.util.log` package to do logging] ## Use Build Automation `[LO-BuildAutomation]` -Note [how the AddressBook app uses Gradle to automate build tasks](UsingGradle.md). +Note [how the malitio app uses Gradle to automate build tasks](UsingGradle.md). **Resources** * Tutorials @@ -108,7 +108,7 @@ Note [how the AddressBook app uses Gradle to automate build tasks](UsingGradle.m ## Use Continuous Integration `[LO-ContinuousIntegration]` -Note [how the AddressBook app uses Travis to perform Continuous Integration](UsingTravis.md). +Note [how the malitio app uses Travis to perform Continuous Integration](UsingTravis.md). **Resources** * Tutorials diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 0cf4b84f7470..5a6bcfdfe983 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,4 +1,4 @@ -# User Guide +# User Guide * [Quick Start](#quick-start) * [Features](#features) @@ -11,18 +11,18 @@ > Having any Java 8 version is not enough.
This app will not work with earlier versions of Java 8. -1. Download the latest `addressbook.jar` from the [releases](../../../releases) tab. -2. Copy the file to the folder you want to use as the home folder for your Address Book. +1. Download the latest `malitio.jar` from the [releases](../../../releases) tab. +2. Copy the file to the folder you want to use as the home folder for your malitio. 3. Double-click the file to start the app. The GUI should appear in a few seconds. - > + > 4. Type the command in the command box and press Enter to execute it.
e.g. typing **`help`** and pressing Enter will open the help window. 5. Some example commands you can try: - * **`list`** : lists all contacts - * **`add`**` John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01` : - adds a contact named `John Doe` to the Address Book. - * **`delete`**` 3` : deletes the 3rd contact shown in the current list + * **`list deadlines`** : lists all deadlines + * **`add`**` drink water` : + adds `drink water` to the to-do-list. + * **`delete`**` e2` : deletes the 2nd event shown in the current schedule list * **`exit`** : exits the app 6. Refer to the [Features](#features) section below for details of each command.
@@ -34,101 +34,244 @@ > * Items in `SQUARE_BRACKETS` are optional. > * Items with `...` after them can have multiple instances. > * The order of parameters is fixed. +> * The following format of DATE/TIME is recognised: 2016-10-24 12pm, Oct 24th noon, day after tomorrow 3pm, next wed. +> * If one of the field of year, month, day or time is not specified, the default is current year/month/day/time. #### Viewing help : `help` Format: `help` > Help is also shown if you enter an incorrect command e.g. `abcd` - -#### Adding a person: `add` -Adds a person to the address book
-Format: `add NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` -> Persons can have any number of tags (including 0) + +#### Adding a task: `add` +Adds a task to the to-do list
+There are three types of tasks that can be added in Malitio: To-Do, Deadline and Event.
+Alphanumeric (alphabets and/or numbers) tags can be added.
+ +Floating Task Format: `add TASK_NAME [t/TAG]`
+Deadline Format: `add TASK_NAME by DATE/TIME [t/TAG]`
+Event Format: `add TASK_NAME start DATE/TIME end DATE/TIME [t/TAG]`
+Note: TASK_NAME cannot contain any of the following key words: "by", "start" and "end".
+ +Examples: +* `add drink water t/healthy` +* `add CS2103 homework by 09-10 1100` +* `add buy present for friend by tomorrow` +* `add lunch with mom start 05-10 1400 end 05-10 1700 t/dontbelate t/restaurant` +* `add wedding dinner start this sat 6pm end this sat 10pm t/buypresent` + + + +#### Listing tasks: `list` +Shows a list of everything in the to-do list.
+Format: `list [tasks|events|deadlines]` + +Shows a list of all events and/or deadlines in the to-do list on and after that date.
+Format: `list [deadlines|events] DATE/TIME` + +Examples: +* `list` +* `list deadlines` +* `list deadlines 05-10 1400` +* `list 05-10 1400` + + +#### List all task from beginning of time: `listall` +List all the task from beginning of time even if those task are already past current time.
+Format: `listall` + +> List all the task from beginning of time Examples: -* `add John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01` -* `add Betsy Crowe p/1234567 e/betsycrowe@gmail.com a/Newgate Prison t/criminal t/friend` -#### Listing all persons : `list` -Shows a list of all persons in the address book.
-Format: `list` +* `listall`
+ List all the task from beginning of time in Malitio. -#### Finding all persons containing any keyword in their name: `find` -Finds persons whose names contain any of the given keywords.
-Format: `find KEYWORD [MORE_KEYWORDS]` + +#### Finding tasks: `find` +Finds all input entries specified by the type (deadlines/ floating tasks/ events) whose names or tags is a substring of the given keywords.
+Find MM-DD-YYY also returns deadlines/events on the specified date time. +If the type is not specified, all entries containing the keyword will be displayed.
+Format: `find [f|d|e] KEYWORD [MORE KEYWORDS]` -> * The search is case sensitive. e.g `hans` will not match `Hans` -> * The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -> * Only the name is searched. -> * Only full words will be matched e.g. `Han` will not match `Hans` -> * Persons matching at least one keyword will be returned (i.e. `OR` search). - e.g. `Hans` will match `Hans Bo` +> * The search is case insensitive. +> * The order of the keywords does not matter. e.g. `Race Car` will match `Car race` +> * Only the task names are searched. +> * Part of the words will be matched e.g. `Han` will match `Hans` +> * Task matching at least one keyword will be returned (i.e. `OR` search). + e.g. `Work` will match `workout daily` Examples: -* `find John`
- Returns `John Doe` but not `john` -* `find Betsy Tim John`
- Returns Any person having names `Betsy`, `Tim`, or `John` +* `find f work`
+ Returns `workout with mom` in floating task list +* `find d lunch`
+ Returns `lunch with mom` in deadlines list +* `find e 10-31-2016`
+ Returns all events that has start or end date as `10-31-2016` +* `find lunch dinner breakfast`
+ Returns all tasks having names `lunch`, `dinner`, or `breakfast` + + +#### Deleting a task : `delete` +Deletes the specified task from lists.
-#### Deleting a person : `delete` -Deletes the specified person from the address book. Irreversible.
Format: `delete INDEX` -> Deletes the person at the specified `INDEX`. +> Deletes the task at the specified `INDEX`. + The index **must have either 'f','d' or 'e' as a prefix and also a positive integer** f1, e2, d3, ...
+ +Examples: +* `delete e2`
+ Deletes the 2nd task in the currently showing events list. +* `delete f1`
+ Deletes the 1st task in the currently showing floating task list. + + + + +#### Edit a task : `edit` +Edits the specified task from the to-do list.
+Edit Floating Task Format: `edit 'f'INDEX [TASK_NAME] [t/TAG]`
+Edit Deadline Format: `edit 'd'INDEX [TASK_NAME] [by DATE/TIME] [t/TAG]`
+Edit Event Format `edit 'e'INDEX [TASK_NAME] [start DATE/TIME] [end DATE/TIME]`
+To remove all tags from a task, use the parameter: t/null
+Note: TASK_NAME cannot contain any of the following key words: "by", "start" and "end".
+ + +> * Edits the task at the specified `INDEX` with the given one or more parameters. +> * The index refers to the index number shown in the most recent listing.
+> * The index **must have either 'f','d' or 'e' as a prefix and also a positive integer** f1, e2, d3, ...
+> * At least one of the optional parameters must be present
+> * The prefix is not case sensitive.
+> * The edit function can only edit the details within the same type of task.
+> * Editting the tags will result in a replacement of all tags.
+ +Examples: +* `edit e1 end 12-21 2359`
+ Edits the 1st event in the schedule list, replacing its original end time with 21 December.
+* `edit f1 lunch with mom`
+ Edits the 1st task in the to-do list, replacing its original name with "lunch with mom".
+* `edit d2 t/wedding t/love`
+ Edits the 2nd deadline in the deadline list, replacing its existing tags with the tags: 'wedding' and 'love'.
+ + + +#### Completing a floating task or deadline: `complete` +complete the specified floating task or deadline from Malitio by striking out them.
+Format: `complete f/d+INDEX` + +> Complete the floating task or deadline at the specified `INDEX`. The index refers to the index number shown in the most recent listing.
- The index **must be a positive integer** 1, 2, 3, ... + The index **must have either 'f' or 'd' as a prefix and also a positive integer** eg. f1, d2, ... Examples: -* `list`
- `delete 2`
- Deletes the 2nd person in the address book. -* `find Betsy`
- `delete 1`
- Deletes the 1st person in the results of the `find` command. - -#### Select a person : `select` -Selects the person identified by the index number used in the last person listing.
-Format: `select INDEX` - -> Selects the person and loads the Google search page the person at the specified `INDEX`. + +* `complete f2`
+ Complete the 2nd floating task in Malitio. +* `complete d1`
+ Complete the 1st deadline in Malitio. + +#### Uncompleting a floating task or deadline: `uncomplete` +complete the specified floating task or deadline from Malitio by unstriking out them.
+Format: `uncomplete f/d+INDEX` + +> Uncomplete the floating task or deadline at the specified `INDEX`. The index refers to the index number shown in the most recent listing.
- The index **must be a positive integer** 1, 2, 3, ... + The index **must have either 'f' or 'd' as a prefix and also a positive integer** eg. f1, d2, ... + +Examples: + +* `uncomplete f2`
+ Complete the 2nd floating task in Malitio. +* `uncomplete d1`
+ Complete the 1st deadline in Malitio. + + + +#### Marking as priority : `mark` +Marks the specified task in the to-do list
+Format: `mark INDEX` + +Examples: +* `mark f1` + +#### Marking as priority : `unmark` +Unmarks the specified task in the to-do list
+Format: `unmark INDEX` + +Examples: +* `unmark f1` + + + +#### Clearing multiple entries : `clear` +Clears multiple entries from Malitio.
+Format: `clear [expired]` Examples: -* `list`
- `select 2`
- Selects the 2nd person in the address book. -* `find Betsy`
- `select 1`
- Selects the 1st person in the results of the `find` command. +* `clear`
+ Clears all entries in Malitio. +* `clear expired`
+ Clears all completed floating tasks and deadlines, and events in the past. + + + +#### Undo the most recent action: `undo` +Undo the most recent data-related command and reverts Malitio to previous state.
+Data-related commands include add, delete, edit, clear, mark, unmark, complete, uncomplete.
+Format: `undo` -#### Clearing all entries : `clear` -Clears all entries from the address book.
-Format: `clear` +#### Redo the most recent action: `redo` +Redo the most recent data-related command and reverts Malitio to previous state before undo.
+Redo will no longer be possible after a new data-related command is executed.
+Data-related commands include add, delete, edit, clear, mark, unmark, complete, uncomplete.
+Format: `redo` + #### Exiting the program : `exit` Exits the program.
Format: `exit` #### Saving the data -Address book data are saved in the hard disk automatically after any command that changes the data.
-There is no need to save manually. +Malitio data are saved in the hard disk automatically after any command that changes the data.
+There is no need to save manually.
+ + +#### Specifying location of local data file: `save` +Users can specify which directory to save their data file. Only valid directory will be created if it does not exist already.
+The old data file will automatically be deleted. +Format: `save DIRECTORY` +* DIRECTORY can be in absolute or relative format + +Example: +* `save C://Users`
+ Saves data in C://Users/malitio.xml + ## FAQ **Q**: How do I transfer my data to another Computer?
**A**: Install the app in the other computer and overwrite the empty data file it creates with - the file that contains the data of your previous Address Book folder. + the file that contains the data of your previous malitio folder. ## Command Summary Command | Format --------- | :-------- -Add | `add NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` -Clear | `clear` -Delete | `delete INDEX` -Find | `find KEYWORD [MORE_KEYWORDS]` -List | `list` -Help | `help` -Select | `select INDEX` +------- | :------- +Add | `add TASK_NAME [by DATE/TIME] [start DATE/TIME end DATE/TIME] [t/TAG]...` +Clear | `clear [expired]` +Delete | `delete [f|d|e]INDEX` +Find | `find KEYWORD [MORE_KEYWORDS] [t/TYPE]` +List | `list` +Listall | `listall` +Edit | `edit [f|d|e]INDEX [NAME] [by DATE/TIME] [start DATE/TIME] [end DATE/TIME] [t/TAG]...` +Complete| `complete [f|d]INDEX` +Uncomplete| `uncomplete [f|d]INDEX` +Mark | `mark [f|d|e]INDEX` +Unmark | `unmark [f|d|e]INDEX` +Help | `help` +Undo | `undo` +Redo | `redo` +Save | `save DIRECTORY` + + diff --git a/docs/UsingGradle.md b/docs/UsingGradle.md index 578c5f8634c2..2efdbe01ff84 100644 --- a/docs/UsingGradle.md +++ b/docs/UsingGradle.md @@ -35,7 +35,7 @@ Gradle commands look like this: ## Creating the JAR file * **`shadowJar`**
- Creates the `addressbook.jar` file in the `build/jar` folder, _if the current file is outdated_.
+ Creates the `malitio.jar` file in the `build/jar` folder, _if the current file is outdated_.
e.g. `./gradlew shadowJar` > To force Gradle to create the JAR file even if the current one is up-to-date, you can '`clean`' first.
diff --git a/docs/diagrams/Bel's Copy - Model.png b/docs/diagrams/Bel's Copy - Model.png new file mode 100644 index 000000000000..9321dd84c53e Binary files /dev/null and b/docs/diagrams/Bel's Copy - Model.png differ diff --git "a/docs/diagrams/Bel\342\200\231s Copy - Model.pptx" "b/docs/diagrams/Bel\342\200\231s Copy - Model.pptx" new file mode 100644 index 000000000000..81e4b91c4053 Binary files /dev/null and "b/docs/diagrams/Bel\342\200\231s Copy - Model.pptx" differ diff --git a/docs/diagrams/Diagrams.pptx b/docs/diagrams/Diagrams.pptx index 3c28abe9c1d3..fb5939a2dcd2 100644 Binary files a/docs/diagrams/Diagrams.pptx and b/docs/diagrams/Diagrams.pptx differ diff --git a/docs/images/AnnabelEng.jpg b/docs/images/AnnabelEng.jpg new file mode 100644 index 000000000000..46fd8d0daf4b Binary files /dev/null and b/docs/images/AnnabelEng.jpg differ diff --git a/docs/images/Architecture.png b/docs/images/Architecture.png index bdc789000f77..398ce55d73ec 100644 Binary files a/docs/images/Architecture.png and b/docs/images/Architecture.png differ diff --git a/docs/images/DamithRajapakse.jpg b/docs/images/DamithRajapakse.jpg deleted file mode 100644 index 127543883893..000000000000 Binary files a/docs/images/DamithRajapakse.jpg and /dev/null differ diff --git a/docs/images/DeletePersonSdForLogic.png b/docs/images/DeletePersonSdForLogic.png index 6c272fb17af6..3ec54b93a645 100644 Binary files a/docs/images/DeletePersonSdForLogic.png and b/docs/images/DeletePersonSdForLogic.png differ diff --git a/docs/images/DesmondKhoo.jpg b/docs/images/DesmondKhoo.jpg new file mode 100644 index 000000000000..3ab8509ecf65 Binary files /dev/null and b/docs/images/DesmondKhoo.jpg differ diff --git a/docs/images/JoshuaLee.jpg b/docs/images/JoshuaLee.jpg deleted file mode 100644 index 2d1d94e0cf5d..000000000000 Binary files a/docs/images/JoshuaLee.jpg and /dev/null differ diff --git a/docs/images/LeowYijin.jpg b/docs/images/LeowYijin.jpg deleted file mode 100644 index adbf62ad9406..000000000000 Binary files a/docs/images/LeowYijin.jpg and /dev/null differ diff --git a/docs/images/MartinChoo.jpg b/docs/images/MartinChoo.jpg deleted file mode 100644 index fd14fb94593a..000000000000 Binary files a/docs/images/MartinChoo.jpg and /dev/null differ diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png index 8cdf11ec93a1..9321dd84c53e 100644 Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ diff --git a/docs/images/NathanKwon.jpg b/docs/images/NathanKwon.jpg new file mode 100644 index 000000000000..e7d40bcc1ee6 Binary files /dev/null and b/docs/images/NathanKwon.jpg differ diff --git a/docs/images/NgHuanRan.jpg b/docs/images/NgHuanRan.jpg new file mode 100644 index 000000000000..e277b7c5b1ca Binary files /dev/null and b/docs/images/NgHuanRan.jpg differ diff --git a/docs/images/SDforDeletePerson.png b/docs/images/SDforDeletePerson.png index 1e836f10dcd8..060b3d41ed8a 100644 Binary files a/docs/images/SDforDeletePerson.png and b/docs/images/SDforDeletePerson.png differ diff --git a/docs/images/SDforDeletePersonEventHandling.png b/docs/images/SDforDeletePersonEventHandling.png index ecec0805d32c..9907c706900c 100644 Binary files a/docs/images/SDforDeletePersonEventHandling.png and b/docs/images/SDforDeletePersonEventHandling.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index 7a4cd2700cbf..d690434af306 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/Ui.jpg b/docs/images/Ui.jpg new file mode 100644 index 000000000000..67172da3b47a Binary files /dev/null and b/docs/images/Ui.jpg differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png deleted file mode 100644 index 7121a50a442a..000000000000 Binary files a/docs/images/Ui.png and /dev/null differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 459245e267af..5ecdd06d29b7 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/YouLiang.jpg b/docs/images/YouLiang.jpg deleted file mode 100644 index 17b48a732272..000000000000 Binary files a/docs/images/YouLiang.jpg and /dev/null differ diff --git a/lib/antlr-runtime-3.5.2.jar b/lib/antlr-runtime-3.5.2.jar new file mode 100644 index 000000000000..d48e3e867968 Binary files /dev/null and b/lib/antlr-runtime-3.5.2.jar differ diff --git a/lib/backport-util-concurrent-3.1.jar b/lib/backport-util-concurrent-3.1.jar new file mode 100644 index 000000000000..3a4c2797abfe Binary files /dev/null and b/lib/backport-util-concurrent-3.1.jar differ diff --git a/lib/commons-codec-1.5.jar b/lib/commons-codec-1.5.jar new file mode 100644 index 000000000000..e9013fed78f3 Binary files /dev/null and b/lib/commons-codec-1.5.jar differ diff --git a/lib/commons-lang-2.6.jar b/lib/commons-lang-2.6.jar new file mode 100644 index 000000000000..98467d3a653e Binary files /dev/null and b/lib/commons-lang-2.6.jar differ diff --git a/lib/commons-logging-1.1.1.jar b/lib/commons-logging-1.1.1.jar new file mode 100644 index 000000000000..1deef144cb17 Binary files /dev/null and b/lib/commons-logging-1.1.1.jar differ diff --git a/lib/ical4j-1.0.2.jar b/lib/ical4j-1.0.2.jar new file mode 100644 index 000000000000..e274bc24f745 Binary files /dev/null and b/lib/ical4j-1.0.2.jar differ diff --git a/lib/natty-0.12.jar b/lib/natty-0.12.jar new file mode 100644 index 000000000000..47644353aac5 Binary files /dev/null and b/lib/natty-0.12.jar differ diff --git a/lib/slf4j-api-1.7.10.jar b/lib/slf4j-api-1.7.10.jar new file mode 100644 index 000000000000..744e9ec5b0d6 Binary files /dev/null and b/lib/slf4j-api-1.7.10.jar differ diff --git a/src/.project b/src/.project new file mode 100644 index 000000000000..ac4db64ed9a1 --- /dev/null +++ b/src/.project @@ -0,0 +1,17 @@ + + + src + Project src created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/src/.settings/org.eclipse.buildship.core.prefs b/src/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000000..97b7cc517bc2 --- /dev/null +++ b/src/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,9 @@ +connection.arguments= +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.gradle.user.home=null +connection.java.home=null +connection.jvm.arguments= +connection.project.dir= +derived.resources=.gradle,build +eclipse.preferences.version=1 +project.path=\: diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java deleted file mode 100644 index 1deb3a1e4695..000000000000 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ /dev/null @@ -1,13 +0,0 @@ -package seedu.address.commons.core; - -/** - * Container for user visible messages. - */ -public class Messages { - - public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; - public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; - public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; - public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; - -} diff --git a/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java b/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java deleted file mode 100644 index 347a8359e0d5..000000000000 --- a/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -package seedu.address.commons.events.model; - -import seedu.address.commons.events.BaseEvent; -import seedu.address.model.ReadOnlyAddressBook; - -/** Indicates the AddressBook in the model has changed*/ -public class AddressBookChangedEvent extends BaseEvent { - - public final ReadOnlyAddressBook data; - - public AddressBookChangedEvent(ReadOnlyAddressBook data){ - this.data = data; - } - - @Override - public String toString() { - return "number of persons " + data.getPersonList().size() + ", number of tags " + data.getTagList().size(); - } -} diff --git a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java b/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java deleted file mode 100644 index 0580d27aecf5..000000000000 --- a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package seedu.address.commons.events.ui; - -import seedu.address.commons.events.BaseEvent; - -/** - * Indicates a request to jump to the list of persons - */ -public class JumpToListRequestEvent extends BaseEvent { - - public final int targetIndex; - - public JumpToListRequestEvent(int targetIndex) { - this.targetIndex = targetIndex; - } - - @Override - public String toString() { - return this.getClass().getSimpleName(); - } - -} diff --git a/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java deleted file mode 100644 index 95377b326fa6..000000000000 --- a/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package seedu.address.commons.events.ui; - -import seedu.address.commons.events.BaseEvent; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * Represents a selection change in the Person List Panel - */ -public class PersonPanelSelectionChangedEvent extends BaseEvent { - - - private final ReadOnlyPerson newSelection; - - public PersonPanelSelectionChangedEvent(ReadOnlyPerson newSelection){ - this.newSelection = newSelection; - } - - @Override - public String toString() { - return this.getClass().getSimpleName(); - } - - public ReadOnlyPerson getNewSelection() { - return newSelection; - } -} diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java deleted file mode 100644 index 2e94740456a6..000000000000 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ /dev/null @@ -1,36 +0,0 @@ -package seedu.address.commons.util; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Arrays; -import java.util.List; - -/** - * Helper functions for handling strings. - */ -public class StringUtil { - public static boolean containsIgnoreCase(String source, String query) { - String[] split = source.toLowerCase().split("\\s+"); - List strings = Arrays.asList(split); - return strings.stream().filter(s -> s.equals(query.toLowerCase())).count() > 0; - } - - /** - * Returns a detailed message of the t, including the stack trace. - */ - public static String getDetails(Throwable t){ - assert t != null; - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - return t.getMessage() + "\n" + sw.toString(); - } - - /** - * Returns true if s represents an unsigned integer e.g. 1, 2, 3, ...
- * Will return false for null, empty string, "-1", "0", "+1", and " 2 " (untrimmed) "3 0" (contains whitespace). - * @param s Should be trimmed. - */ - public static boolean isUnsignedInteger(String s){ - return s != null && s.matches("^0*[1-9]\\d*$"); - } -} diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java deleted file mode 100644 index 4df1bc65cabb..000000000000 --- a/src/main/java/seedu/address/logic/Logic.java +++ /dev/null @@ -1,21 +0,0 @@ -package seedu.address.logic; - -import javafx.collections.ObservableList; -import seedu.address.logic.commands.CommandResult; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * API of the Logic component - */ -public interface Logic { - /** - * Executes the command and returns the result. - * @param commandText The command as entered by the user. - * @return the result of the command execution. - */ - CommandResult execute(String commandText); - - /** Returns the filtered list of persons */ - ObservableList getFilteredPersonList(); - -} diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java deleted file mode 100644 index ce4dc1903cff..000000000000 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ /dev/null @@ -1,41 +0,0 @@ -package seedu.address.logic; - -import javafx.collections.ObservableList; -import seedu.address.commons.core.ComponentManager; -import seedu.address.commons.core.LogsCenter; -import seedu.address.logic.commands.Command; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.parser.Parser; -import seedu.address.model.Model; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.storage.Storage; - -import java.util.logging.Logger; - -/** - * The main LogicManager of the app. - */ -public class LogicManager extends ComponentManager implements Logic { - private final Logger logger = LogsCenter.getLogger(LogicManager.class); - - private final Model model; - private final Parser parser; - - public LogicManager(Model model, Storage storage) { - this.model = model; - this.parser = new Parser(); - } - - @Override - public CommandResult execute(String commandText) { - logger.info("----------------[USER COMMAND][" + commandText + "]"); - Command command = parser.parseCommand(commandText); - command.setData(model); - return command.execute(); - } - - @Override - public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); - } -} diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java deleted file mode 100644 index 2860a9ab2a85..000000000000 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import java.util.HashSet; -import java.util.Set; - -/** - * Adds a person to the address book. - */ -public class AddCommand extends Command { - - public static final String COMMAND_WORD = "add"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. " - + "Parameters: NAME p/PHONE e/EMAIL a/ADDRESS [t/TAG]...\n" - + "Example: " + COMMAND_WORD - + " John Doe p/98765432 e/johnd@gmail.com a/311, Clementi Ave 2, #02-25 t/friends t/owesMoney"; - - public static final String MESSAGE_SUCCESS = "New person added: %1$s"; - public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; - - private final Person toAdd; - - /** - * Convenience constructor using raw values. - * - * @throws IllegalValueException if any of the raw values are invalid - */ - public AddCommand(String name, String phone, String email, String address, Set tags) - throws IllegalValueException { - final Set tagSet = new HashSet<>(); - for (String tagName : tags) { - tagSet.add(new Tag(tagName)); - } - this.toAdd = new Person( - new Name(name), - new Phone(phone), - new Email(email), - new Address(address), - new UniqueTagList(tagSet) - ); - } - - @Override - public CommandResult execute() { - assert model != null; - try { - model.addPerson(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); - } catch (UniquePersonList.DuplicatePersonException e) { - return new CommandResult(MESSAGE_DUPLICATE_PERSON); - } - - } - -} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java deleted file mode 100644 index 522d57189f51..000000000000 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ /dev/null @@ -1,22 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.model.AddressBook; - -/** - * Clears the address book. - */ -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() {} - - - @Override - public CommandResult execute() { - assert model != null; - model.resetData(AddressBook.getEmptyAddressBook()); - return new CommandResult(MESSAGE_SUCCESS); - } -} diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java deleted file mode 100644 index 1bfebe8912a8..000000000000 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ /dev/null @@ -1,50 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.commons.core.Messages; -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList.PersonNotFoundException; - -/** - * Deletes a person identified using it's last displayed index from the address book. - */ -public class DeleteCommand extends Command { - - public static final String COMMAND_WORD = "delete"; - - public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Deletes the person identified by the index number used in the last person listing.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; - - public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; - - public final int targetIndex; - - public DeleteCommand(int targetIndex) { - this.targetIndex = targetIndex; - } - - - @Override - public CommandResult execute() { - - UnmodifiableObservableList lastShownList = model.getFilteredPersonList(); - - if (lastShownList.size() < targetIndex) { - indicateAttemptToExecuteIncorrectCommand(); - return new CommandResult(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - ReadOnlyPerson personToDelete = lastShownList.get(targetIndex - 1); - - try { - model.deletePerson(personToDelete); - } catch (PersonNotFoundException pnfe) { - assert false : "The target person cannot be missing"; - } - - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); - } - -} diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java deleted file mode 100644 index 1d61bf6cc857..000000000000 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ /dev/null @@ -1,30 +0,0 @@ -package seedu.address.logic.commands; - -import java.util.Set; - -/** - * Finds and lists all persons in address book whose name contains any of the argument keywords. - * Keyword matching is case sensitive. - */ -public class FindCommand extends Command { - - public static final String COMMAND_WORD = "find"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of " - + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; - - private final Set keywords; - - public FindCommand(Set keywords) { - this.keywords = keywords; - } - - @Override - public CommandResult execute() { - model.updateFilteredPersonList(keywords); - return new CommandResult(getMessageForPersonListShownSummary(model.getFilteredPersonList().size())); - } - -} diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java deleted file mode 100644 index 9bdd457a1b01..000000000000 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ /dev/null @@ -1,20 +0,0 @@ -package seedu.address.logic.commands; - - -/** - * Lists all persons in the address book to the user. - */ -public class ListCommand extends Command { - - public static final String COMMAND_WORD = "list"; - - public static final String MESSAGE_SUCCESS = "Listed all persons"; - - public ListCommand() {} - - @Override - public CommandResult execute() { - model.updateFilteredListToShowAll(); - return new CommandResult(MESSAGE_SUCCESS); - } -} diff --git a/src/main/java/seedu/address/logic/commands/SelectCommand.java b/src/main/java/seedu/address/logic/commands/SelectCommand.java deleted file mode 100644 index 9ca0551f1951..000000000000 --- a/src/main/java/seedu/address/logic/commands/SelectCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.core.Messages; -import seedu.address.commons.events.ui.JumpToListRequestEvent; -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * Selects a person identified using it's last displayed index from the address book. - */ -public class SelectCommand extends Command { - - public final int targetIndex; - - public static final String COMMAND_WORD = "select"; - - public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Selects the person identified by the index number used in the last person listing.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; - - public static final String MESSAGE_SELECT_PERSON_SUCCESS = "Selected Person: %1$s"; - - public SelectCommand(int targetIndex) { - this.targetIndex = targetIndex; - } - - @Override - public CommandResult execute() { - - UnmodifiableObservableList lastShownList = model.getFilteredPersonList(); - - if (lastShownList.size() < targetIndex) { - indicateAttemptToExecuteIncorrectCommand(); - return new CommandResult(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - EventsCenter.getInstance().post(new JumpToListRequestEvent(targetIndex - 1)); - return new CommandResult(String.format(MESSAGE_SELECT_PERSON_SUCCESS, targetIndex)); - - } - -} diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/address/logic/parser/Parser.java deleted file mode 100644 index 959b2cd0383c..000000000000 --- a/src/main/java/seedu/address/logic/parser/Parser.java +++ /dev/null @@ -1,192 +0,0 @@ -package seedu.address.logic.parser; - -import seedu.address.logic.commands.*; -import seedu.address.commons.util.StringUtil; -import seedu.address.commons.exceptions.IllegalValueException; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; - -/** - * Parses user input. - */ -public class Parser { - - /** - * Used for initial separation of command word and args. - */ - private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); - - private static final Pattern PERSON_INDEX_ARGS_FORMAT = Pattern.compile("(?.+)"); - - private static final Pattern KEYWORDS_ARGS_FORMAT = - Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace - - private static final Pattern PERSON_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes - Pattern.compile("(?[^/]+)" - + " (?p?)p/(?[^/]+)" - + " (?p?)e/(?[^/]+)" - + " (?p?)a/(?
[^/]+)" - + "(?(?: t/[^/]+)*)"); // variable number of tags - - public Parser() {} - - /** - * Parses user input into command for execution. - * - * @param userInput full user input string - * @return the command based on the user input - */ - public Command parseCommand(String userInput) { - final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); - if (!matcher.matches()) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); - } - - final String commandWord = matcher.group("commandWord"); - final String arguments = matcher.group("arguments"); - switch (commandWord) { - - case AddCommand.COMMAND_WORD: - return prepareAdd(arguments); - - case SelectCommand.COMMAND_WORD: - return prepareSelect(arguments); - - case DeleteCommand.COMMAND_WORD: - return prepareDelete(arguments); - - case ClearCommand.COMMAND_WORD: - return new ClearCommand(); - - case FindCommand.COMMAND_WORD: - return prepareFind(arguments); - - case ListCommand.COMMAND_WORD: - return new ListCommand(); - - case ExitCommand.COMMAND_WORD: - return new ExitCommand(); - - case HelpCommand.COMMAND_WORD: - return new HelpCommand(); - - default: - return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); - } - } - - /** - * Parses arguments in the context of the add person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareAdd(String args){ - final Matcher matcher = PERSON_DATA_ARGS_FORMAT.matcher(args.trim()); - // Validate arg string format - if (!matcher.matches()) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); - } - try { - return new AddCommand( - matcher.group("name"), - matcher.group("phone"), - matcher.group("email"), - matcher.group("address"), - getTagsFromArgs(matcher.group("tagArguments")) - ); - } catch (IllegalValueException ive) { - return new IncorrectCommand(ive.getMessage()); - } - } - - /** - * Extracts the new person's tags from the add command's tag arguments string. - * Merges duplicate tag strings. - */ - private static Set getTagsFromArgs(String tagArguments) throws IllegalValueException { - // no tags - if (tagArguments.isEmpty()) { - return Collections.emptySet(); - } - // replace first delimiter prefix, then split - final Collection tagStrings = Arrays.asList(tagArguments.replaceFirst(" t/", "").split(" t/")); - return new HashSet<>(tagStrings); - } - - /** - * Parses arguments in the context of the delete person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareDelete(String args) { - - Optional index = parseIndex(args); - if(!index.isPresent()){ - return new IncorrectCommand( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); - } - - return new DeleteCommand(index.get()); - } - - /** - * Parses arguments in the context of the select person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareSelect(String args) { - Optional index = parseIndex(args); - if(!index.isPresent()){ - return new IncorrectCommand( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE)); - } - - return new SelectCommand(index.get()); - } - - /** - * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index. - * Returns an {@code Optional.empty()} otherwise. - */ - private Optional parseIndex(String command) { - final Matcher matcher = PERSON_INDEX_ARGS_FORMAT.matcher(command.trim()); - if (!matcher.matches()) { - return Optional.empty(); - } - - String index = matcher.group("targetIndex"); - if(!StringUtil.isUnsignedInteger(index)){ - return Optional.empty(); - } - return Optional.of(Integer.parseInt(index)); - - } - - /** - * Parses arguments in the context of the find person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareFind(String args) { - final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); - if (!matcher.matches()) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, - FindCommand.MESSAGE_USAGE)); - } - - // keywords delimited by whitespace - final String[] keywords = matcher.group("keywords").split("\\s+"); - final Set keywordSet = new HashSet<>(Arrays.asList(keywords)); - return new FindCommand(keywordSet); - } - -} \ No newline at end of file diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java deleted file mode 100644 index 298cc1b82ce8..000000000000 --- a/src/main/java/seedu/address/model/AddressBook.java +++ /dev/null @@ -1,163 +0,0 @@ -package seedu.address.model; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * Wraps all data at the address-book level - * Duplicates are not allowed (by .equals comparison) - */ -public class AddressBook implements ReadOnlyAddressBook { - - private final UniquePersonList persons; - private final UniqueTagList tags; - - { - persons = new UniquePersonList(); - tags = new UniqueTagList(); - } - - public AddressBook() {} - - /** - * Persons and Tags are copied into this addressbook - */ - public AddressBook(ReadOnlyAddressBook toBeCopied) { - this(toBeCopied.getUniquePersonList(), toBeCopied.getUniqueTagList()); - } - - /** - * Persons and Tags are copied into this addressbook - */ - public AddressBook(UniquePersonList persons, UniqueTagList tags) { - resetData(persons.getInternalList(), tags.getInternalList()); - } - - public static ReadOnlyAddressBook getEmptyAddressBook() { - return new AddressBook(); - } - -//// list overwrite operations - - public ObservableList getPersons() { - return persons.getInternalList(); - } - - public void setPersons(List persons) { - this.persons.getInternalList().setAll(persons); - } - - public void setTags(Collection tags) { - this.tags.getInternalList().setAll(tags); - } - - public void resetData(Collection newPersons, Collection newTags) { - setPersons(newPersons.stream().map(Person::new).collect(Collectors.toList())); - setTags(newTags); - } - - public void resetData(ReadOnlyAddressBook newData) { - resetData(newData.getPersonList(), newData.getTagList()); - } - -//// person-level operations - - /** - * Adds a person to the address book. - * Also checks the new person's tags and updates {@link #tags} with any new tags found, - * and updates the Tag objects in the person to point to those in {@link #tags}. - * - * @throws UniquePersonList.DuplicatePersonException if an equivalent person already exists. - */ - public void addPerson(Person p) throws UniquePersonList.DuplicatePersonException { - syncTagsWithMasterList(p); - persons.add(p); - } - - /** - * Ensures that every tag in this person: - * - exists in the master list {@link #tags} - * - points to a Tag object in the master list - */ - private void syncTagsWithMasterList(Person person) { - final UniqueTagList personTags = person.getTags(); - tags.mergeFrom(personTags); - - // Create map with values = tag object references in the master list - final Map masterTagObjects = new HashMap<>(); - for (Tag tag : tags) { - masterTagObjects.put(tag, tag); - } - - // Rebuild the list of person tags using references from the master list - final Set commonTagReferences = new HashSet<>(); - for (Tag tag : personTags) { - commonTagReferences.add(masterTagObjects.get(tag)); - } - person.setTags(new UniqueTagList(commonTagReferences)); - } - - public boolean removePerson(ReadOnlyPerson key) throws UniquePersonList.PersonNotFoundException { - if (persons.remove(key)) { - return true; - } else { - throw new UniquePersonList.PersonNotFoundException(); - } - } - -//// tag-level operations - - public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { - tags.add(t); - } - -//// util methods - - @Override - public String toString() { - return persons.getInternalList().size() + " persons, " + tags.getInternalList().size() + " tags"; - // TODO: refine later - } - - @Override - public List getPersonList() { - return Collections.unmodifiableList(persons.getInternalList()); - } - - @Override - public List getTagList() { - return Collections.unmodifiableList(tags.getInternalList()); - } - - @Override - public UniquePersonList getUniquePersonList() { - return this.persons; - } - - @Override - public UniqueTagList getUniqueTagList() { - return this.tags; - } - - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof AddressBook // instanceof handles nulls - && this.persons.equals(((AddressBook) other).persons) - && this.tags.equals(((AddressBook) other).tags)); - } - - @Override - public int hashCode() { - // use this method for custom fields hashing instead of implementing your own - return Objects.hash(persons, tags); - } -} diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java deleted file mode 100644 index d14a27a93b5e..000000000000 --- a/src/main/java/seedu/address/model/Model.java +++ /dev/null @@ -1,35 +0,0 @@ -package seedu.address.model; - -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; - -import java.util.Set; - -/** - * The API of the Model component. - */ -public interface Model { - /** Clears existing backing model and replaces with the provided new data. */ - void resetData(ReadOnlyAddressBook newData); - - /** Returns the AddressBook */ - ReadOnlyAddressBook getAddressBook(); - - /** Deletes the given person. */ - void deletePerson(ReadOnlyPerson target) throws UniquePersonList.PersonNotFoundException; - - /** Adds the given person */ - void addPerson(Person person) throws UniquePersonList.DuplicatePersonException; - - /** Returns the filtered person list as an {@code UnmodifiableObservableList} */ - UnmodifiableObservableList getFilteredPersonList(); - - /** Updates the filter of the filtered person list to show all persons */ - void updateFilteredListToShowAll(); - - /** Updates the filter of the filtered person list to filter by the given keywords*/ - void updateFilteredPersonList(Set keywords); - -} diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java deleted file mode 100644 index 869226d02bf1..000000000000 --- a/src/main/java/seedu/address/model/ModelManager.java +++ /dev/null @@ -1,153 +0,0 @@ -package seedu.address.model; - -import javafx.collections.transformation.FilteredList; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.commons.util.StringUtil; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.core.ComponentManager; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; -import seedu.address.model.person.UniquePersonList.PersonNotFoundException; - -import java.util.Set; -import java.util.logging.Logger; - -/** - * Represents the in-memory model of the address book data. - * All changes to any model should be synchronized. - */ -public class ModelManager extends ComponentManager implements Model { - private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - - private final AddressBook addressBook; - private final FilteredList filteredPersons; - - /** - * Initializes a ModelManager with the given AddressBook - * AddressBook and its variables should not be null - */ - public ModelManager(AddressBook src, UserPrefs userPrefs) { - super(); - assert src != null; - assert userPrefs != null; - - logger.fine("Initializing with address book: " + src + " and user prefs " + userPrefs); - - addressBook = new AddressBook(src); - filteredPersons = new FilteredList<>(addressBook.getPersons()); - } - - public ModelManager() { - this(new AddressBook(), new UserPrefs()); - } - - public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { - addressBook = new AddressBook(initialData); - filteredPersons = new FilteredList<>(addressBook.getPersons()); - } - - @Override - public void resetData(ReadOnlyAddressBook newData) { - addressBook.resetData(newData); - indicateAddressBookChanged(); - } - - @Override - public ReadOnlyAddressBook getAddressBook() { - return addressBook; - } - - /** Raises an event to indicate the model has changed */ - private void indicateAddressBookChanged() { - raise(new AddressBookChangedEvent(addressBook)); - } - - @Override - public synchronized void deletePerson(ReadOnlyPerson target) throws PersonNotFoundException { - addressBook.removePerson(target); - indicateAddressBookChanged(); - } - - @Override - public synchronized void addPerson(Person person) throws UniquePersonList.DuplicatePersonException { - addressBook.addPerson(person); - updateFilteredListToShowAll(); - indicateAddressBookChanged(); - } - - //=========== Filtered Person List Accessors =============================================================== - - @Override - public UnmodifiableObservableList getFilteredPersonList() { - return new UnmodifiableObservableList<>(filteredPersons); - } - - @Override - public void updateFilteredListToShowAll() { - filteredPersons.setPredicate(null); - } - - @Override - public void updateFilteredPersonList(Set keywords){ - updateFilteredPersonList(new PredicateExpression(new NameQualifier(keywords))); - } - - private void updateFilteredPersonList(Expression expression) { - filteredPersons.setPredicate(expression::satisfies); - } - - //========== Inner classes/interfaces used for filtering ================================================== - - interface Expression { - boolean satisfies(ReadOnlyPerson person); - String toString(); - } - - private class PredicateExpression implements Expression { - - private final Qualifier qualifier; - - PredicateExpression(Qualifier qualifier) { - this.qualifier = qualifier; - } - - @Override - public boolean satisfies(ReadOnlyPerson person) { - return qualifier.run(person); - } - - @Override - public String toString() { - return qualifier.toString(); - } - } - - interface Qualifier { - boolean run(ReadOnlyPerson person); - String toString(); - } - - private class NameQualifier implements Qualifier { - private Set nameKeyWords; - - NameQualifier(Set nameKeyWords) { - this.nameKeyWords = nameKeyWords; - } - - @Override - public boolean run(ReadOnlyPerson person) { - return nameKeyWords.stream() - .filter(keyword -> StringUtil.containsIgnoreCase(person.getName().fullName, keyword)) - .findAny() - .isPresent(); - } - - @Override - public String toString() { - return "name=" + String.join(", ", nameKeyWords); - } - } - -} diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java deleted file mode 100644 index bfca099b1e81..000000000000 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ /dev/null @@ -1,30 +0,0 @@ -package seedu.address.model; - - -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import java.util.List; - -/** - * Unmodifiable view of an address book - */ -public interface ReadOnlyAddressBook { - - UniqueTagList getUniqueTagList(); - - UniquePersonList getUniquePersonList(); - - /** - * Returns an unmodifiable view of persons list - */ - List getPersonList(); - - /** - * Returns an unmodifiable view of tags list - */ - List getTagList(); - -} diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java deleted file mode 100644 index a2bd109c005e..000000000000 --- a/src/main/java/seedu/address/model/person/Address.java +++ /dev/null @@ -1,54 +0,0 @@ -package seedu.address.model.person; - - -import seedu.address.commons.exceptions.IllegalValueException; - -/** - * Represents a Person's address in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)} - */ -public class Address { - - public static final String MESSAGE_ADDRESS_CONSTRAINTS = "Person addresses can be in any format"; - public static final String ADDRESS_VALIDATION_REGEX = ".+"; - - public final String value; - - /** - * Validates given address. - * - * @throws IllegalValueException if given address string is invalid. - */ - public Address(String address) throws IllegalValueException { - assert address != null; - if (!isValidAddress(address)) { - throw new IllegalValueException(MESSAGE_ADDRESS_CONSTRAINTS); - } - this.value = address; - } - - /** - * Returns true if a given string is a valid person email. - */ - public static boolean isValidAddress(String test) { - return test.matches(ADDRESS_VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Address // instanceof handles nulls - && this.value.equals(((Address) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} \ No newline at end of file diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java deleted file mode 100644 index 5da4d1078236..000000000000 --- a/src/main/java/seedu/address/model/person/Email.java +++ /dev/null @@ -1,56 +0,0 @@ -package seedu.address.model.person; - - -import seedu.address.commons.exceptions.IllegalValueException; - -/** - * Represents a Person's phone number in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)} - */ -public class Email { - - public static final String MESSAGE_EMAIL_CONSTRAINTS = - "Person emails should be 2 alphanumeric/period strings separated by '@'"; - public static final String EMAIL_VALIDATION_REGEX = "[\\w\\.]+@[\\w\\.]+"; - - public final String value; - - /** - * Validates given email. - * - * @throws IllegalValueException if given email address string is invalid. - */ - public Email(String email) throws IllegalValueException { - assert email != null; - email = email.trim(); - if (!isValidEmail(email)) { - throw new IllegalValueException(MESSAGE_EMAIL_CONSTRAINTS); - } - this.value = email; - } - - /** - * Returns if a given string is a valid person email. - */ - public static boolean isValidEmail(String test) { - return test.matches(EMAIL_VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Email // instanceof handles nulls - && this.value.equals(((Email) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java deleted file mode 100644 index 4f30033e70fe..000000000000 --- a/src/main/java/seedu/address/model/person/Name.java +++ /dev/null @@ -1,55 +0,0 @@ -package seedu.address.model.person; - -import seedu.address.commons.exceptions.IllegalValueException; - -/** - * Represents a Person's name in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} - */ -public class Name { - - public static final String MESSAGE_NAME_CONSTRAINTS = "Person names should be spaces or alphanumeric characters"; - public static final String NAME_VALIDATION_REGEX = "[\\p{Alnum} ]+"; - - public final String fullName; - - /** - * Validates given name. - * - * @throws IllegalValueException if given name string is invalid. - */ - public Name(String name) throws IllegalValueException { - assert name != null; - name = name.trim(); - if (!isValidName(name)) { - throw new IllegalValueException(MESSAGE_NAME_CONSTRAINTS); - } - this.fullName = name; - } - - /** - * Returns true if a given string is a valid person name. - */ - public static boolean isValidName(String test) { - return test.matches(NAME_VALIDATION_REGEX); - } - - - @Override - public String toString() { - return fullName; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Name // instanceof handles nulls - && this.fullName.equals(((Name) other).fullName)); // state check - } - - @Override - public int hashCode() { - return fullName.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java deleted file mode 100644 index 03ffce7d2e79..000000000000 --- a/src/main/java/seedu/address/model/person/Person.java +++ /dev/null @@ -1,90 +0,0 @@ -package seedu.address.model.person; - -import seedu.address.commons.util.CollectionUtil; -import seedu.address.model.tag.UniqueTagList; - -import java.util.Objects; - -/** - * Represents a Person in the address book. - * Guarantees: details are present and not null, field values are validated. - */ -public class Person implements ReadOnlyPerson { - - private Name name; - private Phone phone; - private Email email; - private Address address; - - private UniqueTagList tags; - - /** - * Every field must be present and not null. - */ - public Person(Name name, Phone phone, Email email, Address address, UniqueTagList tags) { - assert !CollectionUtil.isAnyNull(name, phone, email, address, tags); - this.name = name; - this.phone = phone; - this.email = email; - this.address = address; - this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list - } - - /** - * Copy constructor. - */ - public Person(ReadOnlyPerson source) { - this(source.getName(), source.getPhone(), source.getEmail(), source.getAddress(), source.getTags()); - } - - @Override - public Name getName() { - return name; - } - - @Override - public Phone getPhone() { - return phone; - } - - @Override - public Email getEmail() { - return email; - } - - @Override - public Address getAddress() { - return address; - } - - @Override - public UniqueTagList getTags() { - return new UniqueTagList(tags); - } - - /** - * Replaces this person's tags with the tags in the argument tag list. - */ - public void setTags(UniqueTagList replacement) { - tags.setTags(replacement); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof ReadOnlyPerson // instanceof handles nulls - && this.isSameStateAs((ReadOnlyPerson) other)); - } - - @Override - public int hashCode() { - // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); - } - - @Override - public String toString() { - return getAsText(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java deleted file mode 100644 index d27b2244b727..000000000000 --- a/src/main/java/seedu/address/model/person/Phone.java +++ /dev/null @@ -1,54 +0,0 @@ -package seedu.address.model.person; - -import seedu.address.commons.exceptions.IllegalValueException; - -/** - * Represents a Person's phone number in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)} - */ -public class Phone { - - public static final String MESSAGE_PHONE_CONSTRAINTS = "Person phone numbers should only contain numbers"; - public static final String PHONE_VALIDATION_REGEX = "\\d+"; - - public final String value; - - /** - * Validates given phone number. - * - * @throws IllegalValueException if given phone string is invalid. - */ - public Phone(String phone) throws IllegalValueException { - assert phone != null; - phone = phone.trim(); - if (!isValidPhone(phone)) { - throw new IllegalValueException(MESSAGE_PHONE_CONSTRAINTS); - } - this.value = phone; - } - - /** - * Returns true if a given string is a valid person phone number. - */ - public static boolean isValidPhone(String test) { - return test.matches(PHONE_VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Phone // instanceof handles nulls - && this.value.equals(((Phone) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java deleted file mode 100644 index 263f1fcc7dd5..000000000000 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ /dev/null @@ -1,98 +0,0 @@ -package seedu.address.model.person; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.commons.exceptions.DuplicateDataException; - -import java.util.*; - -/** - * A list of persons that enforces uniqueness between its elements and does not allow nulls. - * - * Supports a minimal set of list operations. - * - * @see Person#equals(Object) - * @see CollectionUtil#elementsAreUnique(Collection) - */ -public class UniquePersonList implements Iterable { - - /** - * Signals that an operation would have violated the 'no duplicates' property of the list. - */ - public static class DuplicatePersonException extends DuplicateDataException { - protected DuplicatePersonException() { - super("Operation would result in duplicate persons"); - } - } - - /** - * Signals that an operation targeting a specified person in the list would fail because - * there is no such matching person in the list. - */ - public static class PersonNotFoundException extends Exception {} - - private final ObservableList internalList = FXCollections.observableArrayList(); - - /** - * Constructs empty PersonList. - */ - public UniquePersonList() {} - - /** - * Returns true if the list contains an equivalent person as the given argument. - */ - public boolean contains(ReadOnlyPerson toCheck) { - assert toCheck != null; - return internalList.contains(toCheck); - } - - /** - * Adds a person to the list. - * - * @throws DuplicatePersonException if the person to add is a duplicate of an existing person in the list. - */ - public void add(Person toAdd) throws DuplicatePersonException { - assert toAdd != null; - if (contains(toAdd)) { - throw new DuplicatePersonException(); - } - internalList.add(toAdd); - } - - /** - * Removes the equivalent person from the list. - * - * @throws PersonNotFoundException if no such person could be found in the list. - */ - public boolean remove(ReadOnlyPerson toRemove) throws PersonNotFoundException { - assert toRemove != null; - final boolean personFoundAndDeleted = internalList.remove(toRemove); - if (!personFoundAndDeleted) { - throw new PersonNotFoundException(); - } - return personFoundAndDeleted; - } - - public ObservableList getInternalList() { - return internalList; - } - - @Override - public Iterator iterator() { - return internalList.iterator(); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof UniquePersonList // instanceof handles nulls - && this.internalList.equals( - ((UniquePersonList) other).internalList)); - } - - @Override - public int hashCode() { - return internalList.hashCode(); - } -} diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java deleted file mode 100644 index 80033086985b..000000000000 --- a/src/main/java/seedu/address/storage/AddressBookStorage.java +++ /dev/null @@ -1,44 +0,0 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; - -import java.io.IOException; -import java.util.Optional; - -/** - * Represents a storage for {@link seedu.address.model.AddressBook}. - */ -public interface AddressBookStorage { - - /** - * Returns the file path of the data file. - */ - String getAddressBookFilePath(); - - /** - * Returns AddressBook data as a {@link ReadOnlyAddressBook}. - * Returns {@code Optional.empty()} if storage file is not found. - * @throws DataConversionException if the data in storage is not in the expected format. - * @throws IOException if there was any problem when reading from the storage. - */ - Optional readAddressBook() throws DataConversionException, IOException; - - /** - * @see #getAddressBookFilePath() - */ - Optional readAddressBook(String filePath) throws DataConversionException, IOException; - - /** - * Saves the given {@link ReadOnlyAddressBook} to the storage. - * @param addressBook cannot be null. - * @throws IOException if there was any problem writing to the file. - */ - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; - - /** - * @see #saveAddressBook(ReadOnlyAddressBook) - */ - void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) throws IOException; - -} diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java deleted file mode 100644 index 91002a8a821a..000000000000 --- a/src/main/java/seedu/address/storage/Storage.java +++ /dev/null @@ -1,39 +0,0 @@ -package seedu.address.storage; - -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Optional; - -/** - * API of the Storage component - */ -public interface Storage extends AddressBookStorage, UserPrefsStorage { - - @Override - Optional readUserPrefs() throws DataConversionException, IOException; - - @Override - void saveUserPrefs(UserPrefs userPrefs) throws IOException; - - @Override - String getAddressBookFilePath(); - - @Override - Optional readAddressBook() throws DataConversionException, IOException; - - @Override - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; - - /** - * Saves the current version of the Address Book to the hard disk. - * Creates the data file if it is missing. - * Raises {@link DataSavingExceptionEvent} if there was an error during saving. - */ - void handleAddressBookChangedEvent(AddressBookChangedEvent abce); -} diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java deleted file mode 100644 index ba1f72f15c27..000000000000 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ /dev/null @@ -1,91 +0,0 @@ -package seedu.address.storage; - -import com.google.common.eventbus.Subscribe; -import seedu.address.commons.core.ComponentManager; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Optional; -import java.util.logging.Logger; - -/** - * Manages storage of AddressBook data in local storage. - */ -public class StorageManager extends ComponentManager implements Storage { - - private static final Logger logger = LogsCenter.getLogger(StorageManager.class); - private AddressBookStorage addressBookStorage; - private UserPrefsStorage userPrefsStorage; - - - public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) { - super(); - this.addressBookStorage = addressBookStorage; - this.userPrefsStorage = userPrefsStorage; - } - - public StorageManager(String addressBookFilePath, String userPrefsFilePath) { - this(new XmlAddressBookStorage(addressBookFilePath), new JsonUserPrefsStorage(userPrefsFilePath)); - } - - // ================ UserPrefs methods ============================== - - @Override - public Optional readUserPrefs() throws DataConversionException, IOException { - return userPrefsStorage.readUserPrefs(); - } - - @Override - public void saveUserPrefs(UserPrefs userPrefs) throws IOException { - userPrefsStorage.saveUserPrefs(userPrefs); - } - - - // ================ AddressBook methods ============================== - - @Override - public String getAddressBookFilePath() { - return addressBookStorage.getAddressBookFilePath(); - } - - @Override - public Optional readAddressBook() throws DataConversionException, IOException { - return readAddressBook(addressBookStorage.getAddressBookFilePath()); - } - - @Override - public Optional readAddressBook(String filePath) throws DataConversionException, IOException { - logger.fine("Attempting to read data from file: " + filePath); - return addressBookStorage.readAddressBook(filePath); - } - - @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { - saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath()); - } - - @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) throws IOException { - logger.fine("Attempting to write to data file: " + filePath); - addressBookStorage.saveAddressBook(addressBook, filePath); - } - - - @Override - @Subscribe - public void handleAddressBookChangedEvent(AddressBookChangedEvent event) { - logger.info(LogsCenter.getEventHandlingLogMessage(event, "Local data changed, saving to file")); - try { - saveAddressBook(event.data); - } catch (IOException e) { - raise(new DataSavingExceptionEvent(e)); - } - } - -} diff --git a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java b/src/main/java/seedu/address/storage/XmlAdaptedPerson.java deleted file mode 100644 index f2167ec201b4..000000000000 --- a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java +++ /dev/null @@ -1,68 +0,0 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import javax.xml.bind.annotation.XmlElement; -import java.util.ArrayList; -import java.util.List; - -/** - * JAXB-friendly version of the Person. - */ -public class XmlAdaptedPerson { - - @XmlElement(required = true) - private String name; - @XmlElement(required = true) - private String phone; - @XmlElement(required = true) - private String email; - @XmlElement(required = true) - private String address; - - @XmlElement - private List tagged = new ArrayList<>(); - - /** - * No-arg constructor for JAXB use. - */ - public XmlAdaptedPerson() {} - - - /** - * Converts a given Person into this class for JAXB use. - * - * @param source future changes to this will not affect the created XmlAdaptedPerson - */ - public XmlAdaptedPerson(ReadOnlyPerson source) { - name = source.getName().fullName; - phone = source.getPhone().value; - email = source.getEmail().value; - address = source.getAddress().value; - tagged = new ArrayList<>(); - for (Tag tag : source.getTags()) { - tagged.add(new XmlAdaptedTag(tag)); - } - } - - /** - * Converts this jaxb-friendly adapted person object into the model's Person object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted person - */ - public Person toModelType() throws IllegalValueException { - final List personTags = new ArrayList<>(); - for (XmlAdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - final Name name = new Name(this.name); - final Phone phone = new Phone(this.phone); - final Email email = new Email(this.email); - final Address address = new Address(this.address); - final UniqueTagList tags = new UniqueTagList(personTags); - return new Person(name, phone, email, address, tags); - } -} diff --git a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java b/src/main/java/seedu/address/storage/XmlAddressBookStorage.java deleted file mode 100644 index 30cb00270cc4..000000000000 --- a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java +++ /dev/null @@ -1,73 +0,0 @@ -package seedu.address.storage; - -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.ReadOnlyAddressBook; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Optional; -import java.util.logging.Logger; - -/** - * A class to access AddressBook data stored as an xml file on the hard disk. - */ -public class XmlAddressBookStorage implements AddressBookStorage { - - private static final Logger logger = LogsCenter.getLogger(XmlAddressBookStorage.class); - - private String filePath; - - public XmlAddressBookStorage(String filePath){ - this.filePath = filePath; - } - - public String getAddressBookFilePath(){ - return filePath; - } - - /** - * Similar to {@link #readAddressBook()} - * @param filePath location of the data. Cannot be null - * @throws DataConversionException if the file is not in the correct format. - */ - public Optional readAddressBook(String filePath) throws DataConversionException, FileNotFoundException { - assert filePath != null; - - File addressBookFile = new File(filePath); - - if (!addressBookFile.exists()) { - logger.info("AddressBook file " + addressBookFile + " not found"); - return Optional.empty(); - } - - ReadOnlyAddressBook addressBookOptional = XmlFileStorage.loadDataFromSaveFile(new File(filePath)); - - return Optional.of(addressBookOptional); - } - - /** - * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)} - * @param filePath location of the data. Cannot be null - */ - public void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) throws IOException { - assert addressBook != null; - assert filePath != null; - - File file = new File(filePath); - FileUtil.createIfMissing(file); - XmlFileStorage.saveDataToFile(file, new XmlSerializableAddressBook(addressBook)); - } - - @Override - public Optional readAddressBook() throws DataConversionException, IOException { - return readAddressBook(filePath); - } - - @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { - saveAddressBook(addressBook, filePath); - } -} diff --git a/src/main/java/seedu/address/storage/XmlSerializableAddressBook.java b/src/main/java/seedu/address/storage/XmlSerializableAddressBook.java deleted file mode 100644 index b7ec533a3a1e..000000000000 --- a/src/main/java/seedu/address/storage/XmlSerializableAddressBook.java +++ /dev/null @@ -1,88 +0,0 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -/** - * An Immutable AddressBook that is serializable to XML format - */ -@XmlRootElement(name = "addressbook") -public class XmlSerializableAddressBook implements ReadOnlyAddressBook { - - @XmlElement - private List persons; - @XmlElement - private List tags; - - { - persons = new ArrayList<>(); - tags = new ArrayList<>(); - } - - /** - * Empty constructor required for marshalling - */ - public XmlSerializableAddressBook() {} - - /** - * Conversion - */ - public XmlSerializableAddressBook(ReadOnlyAddressBook src) { - persons.addAll(src.getPersonList().stream().map(XmlAdaptedPerson::new).collect(Collectors.toList())); - tags = src.getTagList(); - } - - @Override - public UniqueTagList getUniqueTagList() { - try { - return new UniqueTagList(tags); - } catch (UniqueTagList.DuplicateTagException e) { - //TODO: better error handling - e.printStackTrace(); - return null; - } - } - - @Override - public UniquePersonList getUniquePersonList() { - UniquePersonList lists = new UniquePersonList(); - for (XmlAdaptedPerson p : persons) { - try { - lists.add(p.toModelType()); - } catch (IllegalValueException e) { - //TODO: better error handling - } - } - return lists; - } - - @Override - public List getPersonList() { - return persons.stream().map(p -> { - try { - return p.toModelType(); - } catch (IllegalValueException e) { - e.printStackTrace(); - //TODO: better error handling - return null; - } - }).collect(Collectors.toCollection(ArrayList::new)); - } - - @Override - public List getTagList() { - return Collections.unmodifiableList(tags); - } - -} diff --git a/src/main/java/seedu/address/ui/BrowserPanel.java b/src/main/java/seedu/address/ui/BrowserPanel.java deleted file mode 100644 index 54b88318019b..000000000000 --- a/src/main/java/seedu/address/ui/BrowserPanel.java +++ /dev/null @@ -1,68 +0,0 @@ -package seedu.address.ui; - -import javafx.event.Event; -import javafx.scene.Node; -import javafx.scene.layout.AnchorPane; -import javafx.scene.web.WebView; -import seedu.address.commons.util.FxViewUtil; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.commons.core.LogsCenter; - -import java.util.logging.Logger; - -/** - * The Browser Panel of the App. - */ -public class BrowserPanel extends UiPart{ - - private static Logger logger = LogsCenter.getLogger(BrowserPanel.class); - private WebView browser; - - /** - * Constructor is kept private as {@link #load(AnchorPane)} is the only way to create a BrowserPanel. - */ - private BrowserPanel() { - - } - - @Override - public void setNode(Node node) { - //not applicable - } - - @Override - public String getFxmlPath() { - return null; //not applicable - } - - /** - * Factory method for creating a Browser Panel. - * This method should be called after the FX runtime is initialized and in FX application thread. - * @param placeholder The AnchorPane where the BrowserPanel must be inserted - */ - public static BrowserPanel load(AnchorPane placeholder){ - logger.info("Initializing browser"); - BrowserPanel browserPanel = new BrowserPanel(); - browserPanel.browser = new WebView(); - placeholder.setOnKeyPressed(Event::consume); // To prevent triggering events for typing inside the loaded Web page. - FxViewUtil.applyAnchorBoundaryParameters(browserPanel.browser, 0.0, 0.0, 0.0, 0.0); - placeholder.getChildren().add(browserPanel.browser); - return browserPanel; - } - - public void loadPersonPage(ReadOnlyPerson person) { - loadPage("https://www.google.com.sg/#safe=off&q=" + person.getName().fullName.replaceAll(" ", "+")); - } - - public void loadPage(String url){ - browser.getEngine().load(url); - } - - /** - * Frees resources allocated to the browser. - */ - public void freeResources() { - browser = null; - } - -} diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java deleted file mode 100644 index 259e9ad0d333..000000000000 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ /dev/null @@ -1,65 +0,0 @@ -package seedu.address.ui; - -import javafx.fxml.FXML; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import seedu.address.model.person.ReadOnlyPerson; - -public class PersonCard extends UiPart{ - - private static final String FXML = "PersonListCard.fxml"; - - @FXML - private HBox cardPane; - @FXML - private Label name; - @FXML - private Label id; - @FXML - private Label phone; - @FXML - private Label address; - @FXML - private Label email; - @FXML - private Label tags; - - private ReadOnlyPerson person; - private int displayedIndex; - - public PersonCard(){ - - } - - public static PersonCard load(ReadOnlyPerson person, int displayedIndex){ - PersonCard card = new PersonCard(); - card.person = person; - card.displayedIndex = displayedIndex; - return UiPartLoader.loadUiPart(card); - } - - @FXML - public void initialize() { - name.setText(person.getName().fullName); - id.setText(displayedIndex + ". "); - phone.setText(person.getPhone().value); - address.setText(person.getAddress().value); - email.setText(person.getEmail().value); - tags.setText(person.tagsString()); - } - - public HBox getLayout() { - return cardPane; - } - - @Override - public void setNode(Node node) { - cardPane = (HBox)node; - } - - @Override - public String getFxmlPath() { - return FXML; - } -} diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java deleted file mode 100644 index 27d9381c47b5..000000000000 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ /dev/null @@ -1,108 +0,0 @@ -package seedu.address.ui; - -import javafx.application.Platform; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.Node; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.SplitPane; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.VBox; -import javafx.stage.Stage; -import seedu.address.commons.events.ui.PersonPanelSelectionChangedEvent; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.commons.core.LogsCenter; - -import java.util.logging.Logger; - -/** - * Panel containing the list of persons. - */ -public class PersonListPanel extends UiPart { - private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); - private static final String FXML = "PersonListPanel.fxml"; - private VBox panel; - private AnchorPane placeHolderPane; - - @FXML - private ListView personListView; - - public PersonListPanel() { - super(); - } - - @Override - public void setNode(Node node) { - panel = (VBox) node; - } - - @Override - public String getFxmlPath() { - return FXML; - } - - @Override - public void setPlaceholder(AnchorPane pane) { - this.placeHolderPane = pane; - } - - public static PersonListPanel load(Stage primaryStage, AnchorPane personListPlaceholder, - ObservableList personList) { - PersonListPanel personListPanel = - UiPartLoader.loadUiPart(primaryStage, personListPlaceholder, new PersonListPanel()); - personListPanel.configure(personList); - return personListPanel; - } - - private void configure(ObservableList personList) { - setConnections(personList); - addToPlaceholder(); - } - - private void setConnections(ObservableList personList) { - personListView.setItems(personList); - personListView.setCellFactory(listView -> new PersonListViewCell()); - setEventHandlerForSelectionChangeEvent(); - } - - private void addToPlaceholder() { - SplitPane.setResizableWithParent(placeHolderPane, false); - placeHolderPane.getChildren().add(panel); - } - - private void setEventHandlerForSelectionChangeEvent() { - personListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null) { - logger.fine("Selection in person list panel changed to : '" + newValue + "'"); - raise(new PersonPanelSelectionChangedEvent(newValue)); - } - }); - } - - public void scrollTo(int index) { - Platform.runLater(() -> { - personListView.scrollTo(index); - personListView.getSelectionModel().clearAndSelect(index); - }); - } - - class PersonListViewCell extends ListCell { - - public PersonListViewCell() { - } - - @Override - protected void updateItem(ReadOnlyPerson person, boolean empty) { - super.updateItem(person, empty); - - if (empty || person == null) { - setGraphic(null); - setText(null); - } else { - setGraphic(PersonCard.load(person, getIndex() + 1).getLayout()); - } - } - } - -} diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/malitio/MainApp.java similarity index 72% rename from src/main/java/seedu/address/MainApp.java rename to src/main/java/seedu/malitio/MainApp.java index 36dc72a74b7a..df17a436e2d7 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/malitio/MainApp.java @@ -1,24 +1,24 @@ -package seedu.address; +package seedu.malitio; import com.google.common.eventbus.Subscribe; import javafx.application.Application; import javafx.application.Platform; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.Version; -import seedu.address.commons.events.ui.ExitAppRequestEvent; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; -import seedu.address.logic.LogicManager; -import seedu.address.model.*; -import seedu.address.commons.util.ConfigUtil; -import seedu.address.storage.Storage; -import seedu.address.storage.StorageManager; -import seedu.address.ui.Ui; -import seedu.address.ui.UiManager; +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.core.Version; +import seedu.malitio.commons.events.ui.ExitAppRequestEvent; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.ConfigUtil; +import seedu.malitio.commons.util.StringUtil; +import seedu.malitio.logic.Logic; +import seedu.malitio.logic.LogicManager; +import seedu.malitio.model.*; +import seedu.malitio.storage.Storage; +import seedu.malitio.storage.StorageManager; +import seedu.malitio.ui.Ui; +import seedu.malitio.ui.UiManager; import java.io.FileNotFoundException; import java.io.IOException; @@ -32,7 +32,7 @@ public class MainApp extends Application { private static final Logger logger = LogsCenter.getLogger(MainApp.class); - public static final Version VERSION = new Version(1, 0, 0, true); + public static final Version VERSION = new Version(0, 4, 0, true); protected Ui ui; protected Logic logic; @@ -45,45 +45,58 @@ public MainApp() {} @Override public void init() throws Exception { - logger.info("=============================[ Initializing AddressBook ]==========================="); + logger.info("=============================[ Initializing Malitio ]==========================="); super.init(); config = initConfig(getApplicationParameter("config")); - storage = new StorageManager(config.getAddressBookFilePath(), config.getUserPrefsFilePath()); + storage = new StorageManager(config.getMalitioFilePath(), config.getUserPrefsFilePath()); userPrefs = initPrefs(config); initLogging(config); model = initModelManager(storage, userPrefs); - + + updateModel(); + logic = new LogicManager(model, storage); ui = new UiManager(logic, config, userPrefs); initEventsCenter(); } - + + //@@author A0122460W + /** + * update to show relevant deadline and events past current time and date + */ + private void updateModel() { + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + model.updateFilteredTaskListToShowAll(); + } + + //@@author private String getApplicationParameter(String parameterName){ Map applicationParameters = getParameters().getNamed(); return applicationParameters.get(parameterName); } private Model initModelManager(Storage storage, UserPrefs userPrefs) { - Optional addressBookOptional; - ReadOnlyAddressBook initialData; + Optional malitioOptional; + ReadOnlyMalitio initialData; try { - addressBookOptional = storage.readAddressBook(); - if(!addressBookOptional.isPresent()){ - logger.info("Data file not found. Will be starting with an empty AddressBook"); + malitioOptional = storage.readMalitio(); + if(!malitioOptional.isPresent()){ + logger.info("Data file not found. Will be starting with an empty Malitio"); } - initialData = addressBookOptional.orElse(new AddressBook()); + initialData = malitioOptional.orElse(new Malitio()); } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Data file not in the correct format. Will be starting with an empty Malitio"); + initialData = new Malitio(); } catch (IOException e) { - logger.warning("Problem while reading from the file. . Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Problem while reading from the file. . Will be starting with an empty Malitio"); + initialData = new Malitio(); } return new ModelManager(initialData, userPrefs); @@ -139,7 +152,7 @@ protected UserPrefs initPrefs(Config config) { "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. . Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. . Will be starting with an empty Malitio"); initializedPrefs = new UserPrefs(); } @@ -159,13 +172,13 @@ private void initEventsCenter() { @Override public void start(Stage primaryStage) { - logger.info("Starting AddressBook " + MainApp.VERSION); + logger.info("Starting Malitio " + MainApp.VERSION); ui.start(primaryStage); } @Override public void stop() { - logger.info("============================ [ Stopping Address Book ] ============================="); + logger.info("============================ [ Stopping Malitio ] ============================="); ui.stop(); try { storage.saveUserPrefs(userPrefs); diff --git a/src/main/java/seedu/address/commons/core/ComponentManager.java b/src/main/java/seedu/malitio/commons/core/ComponentManager.java similarity index 87% rename from src/main/java/seedu/address/commons/core/ComponentManager.java rename to src/main/java/seedu/malitio/commons/core/ComponentManager.java index 4bc8564e5824..00b576e9a3c5 100644 --- a/src/main/java/seedu/address/commons/core/ComponentManager.java +++ b/src/main/java/seedu/malitio/commons/core/ComponentManager.java @@ -1,6 +1,6 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; -import seedu.address.commons.events.BaseEvent; +import seedu.malitio.commons.events.BaseEvent; /** * Base class for *Manager classes diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/malitio/commons/core/Config.java similarity index 65% rename from src/main/java/seedu/address/commons/core/Config.java rename to src/main/java/seedu/malitio/commons/core/Config.java index 6441c9ef20f4..92695a042f4c 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/seedu/malitio/commons/core/Config.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import java.util.Objects; import java.util.logging.Level; @@ -9,13 +9,15 @@ public class Config { public static final String DEFAULT_CONFIG_FILE = "config.json"; + public static final String DEFAULT_FILE_NAME = "malitio.xml"; + public static final String DEFAULT_FILE_PATH = "data/"; // Config values customizable through config file - private String appTitle = "Address App"; + private String appTitle = "Malitio"; private Level logLevel = Level.INFO; private String userPrefsFilePath = "preferences.json"; - private String addressBookFilePath = "data/addressbook.xml"; - private String addressBookName = "MyAddressBook"; + private String malitioFilePath = DEFAULT_FILE_PATH + DEFAULT_FILE_NAME; + private String malitioName = "MyMalitio"; public Config() { @@ -45,20 +47,20 @@ public void setUserPrefsFilePath(String userPrefsFilePath) { this.userPrefsFilePath = userPrefsFilePath; } - public String getAddressBookFilePath() { - return addressBookFilePath; + public String getMalitioFilePath() { + return malitioFilePath; } - public void setAddressBookFilePath(String addressBookFilePath) { - this.addressBookFilePath = addressBookFilePath; + public void setMalitioFilePath(String malitioFilePath) { + this.malitioFilePath = malitioFilePath; } - public String getAddressBookName() { - return addressBookName; + public String getMalitioName() { + return malitioName; } - public void setAddressBookName(String addressBookName) { - this.addressBookName = addressBookName; + public void setMalitioName(String malitioName) { + this.malitioName = malitioName; } @@ -76,13 +78,13 @@ public boolean equals(Object other) { return Objects.equals(appTitle, o.appTitle) && Objects.equals(logLevel, o.logLevel) && Objects.equals(userPrefsFilePath, o.userPrefsFilePath) - && Objects.equals(addressBookFilePath, o.addressBookFilePath) - && Objects.equals(addressBookName, o.addressBookName); + && Objects.equals(malitioFilePath, o.malitioFilePath) + && Objects.equals(malitioName, o.malitioName); } @Override public int hashCode() { - return Objects.hash(appTitle, logLevel, userPrefsFilePath, addressBookFilePath, addressBookName); + return Objects.hash(appTitle, logLevel, userPrefsFilePath, malitioFilePath, malitioName); } @Override @@ -91,8 +93,8 @@ public String toString(){ sb.append("App title : " + appTitle); sb.append("\nCurrent log level : " + logLevel); sb.append("\nPreference file Location : " + userPrefsFilePath); - sb.append("\nLocal data file location : " + addressBookFilePath); - sb.append("\nAddressBook name : " + addressBookName); + sb.append("\nLocal data file location : " + malitioFilePath); + sb.append("\nMalitio name : " + malitioName); return sb.toString(); } diff --git a/src/main/java/seedu/address/commons/core/EventsCenter.java b/src/main/java/seedu/malitio/commons/core/EventsCenter.java similarity index 92% rename from src/main/java/seedu/address/commons/core/EventsCenter.java rename to src/main/java/seedu/malitio/commons/core/EventsCenter.java index 9652cd5c227b..b7ebc4409afa 100644 --- a/src/main/java/seedu/address/commons/core/EventsCenter.java +++ b/src/main/java/seedu/malitio/commons/core/EventsCenter.java @@ -1,7 +1,8 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import com.google.common.eventbus.EventBus; -import seedu.address.commons.events.BaseEvent; + +import seedu.malitio.commons.events.BaseEvent; import java.util.logging.Logger; diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/malitio/commons/core/GuiSettings.java similarity index 98% rename from src/main/java/seedu/address/commons/core/GuiSettings.java rename to src/main/java/seedu/malitio/commons/core/GuiSettings.java index e157ac8b8679..75de09541106 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/seedu/malitio/commons/core/GuiSettings.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import java.awt.*; import java.io.Serializable; diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/malitio/commons/core/LogsCenter.java similarity index 96% rename from src/main/java/seedu/address/commons/core/LogsCenter.java rename to src/main/java/seedu/malitio/commons/core/LogsCenter.java index 17939bab4975..cfee487380f5 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/seedu/malitio/commons/core/LogsCenter.java @@ -1,10 +1,10 @@ -package seedu.address.commons.core; - -import seedu.address.commons.events.BaseEvent; +package seedu.malitio.commons.core; import java.io.IOException; import java.util.logging.*; +import seedu.malitio.commons.events.BaseEvent; + /** * Configures and manages loggers and handlers, including their logging level * Named {@link Logger}s can be obtained from this class
@@ -15,7 +15,7 @@ public class LogsCenter { private static final int MAX_FILE_COUNT = 5; private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB - private static final String LOG_FILE = "addressbook.log"; + private static final String LOG_FILE = "malitio.log"; private static Level currentLogLevel = Level.INFO; private static final Logger logger = LogsCenter.getLogger(LogsCenter.class); private static FileHandler fileHandler; diff --git a/src/main/java/seedu/malitio/commons/core/Messages.java b/src/main/java/seedu/malitio/commons/core/Messages.java new file mode 100644 index 000000000000..103ac2a0de15 --- /dev/null +++ b/src/main/java/seedu/malitio/commons/core/Messages.java @@ -0,0 +1,14 @@ +package seedu.malitio.commons.core; + +/** + * Container for user visible messages. + */ +public class Messages { + + public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; + public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; + public static final String MESSAGE_INVALID_TASK_DISPLAYED_INDEX = "The task index provided is invalid"; + public static final String MESSAGE_TASKS_LISTED_OVERVIEW = "%1$d tasks found!"; + public static final String MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX = "The deadline index provided is invalid"; + public static final String MESSAGE_INVALID_EVENT_DISPLAYED_INDEX = "The event index provided is invalid"; +} diff --git a/src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java b/src/main/java/seedu/malitio/commons/core/UnmodifiableObservableList.java similarity index 99% rename from src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java rename to src/main/java/seedu/malitio/commons/core/UnmodifiableObservableList.java index 5c25d8647a8d..31e6cafff35f 100644 --- a/src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java +++ b/src/main/java/seedu/malitio/commons/core/UnmodifiableObservableList.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import javafx.beans.InvalidationListener; import javafx.collections.ListChangeListener; diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/malitio/commons/core/Version.java similarity index 98% rename from src/main/java/seedu/address/commons/core/Version.java rename to src/main/java/seedu/malitio/commons/core/Version.java index 7ecb85b18f82..b59252850c41 100644 --- a/src/main/java/seedu/address/commons/core/Version.java +++ b/src/main/java/seedu/malitio/commons/core/Version.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/seedu/address/commons/events/BaseEvent.java b/src/main/java/seedu/malitio/commons/events/BaseEvent.java similarity index 90% rename from src/main/java/seedu/address/commons/events/BaseEvent.java rename to src/main/java/seedu/malitio/commons/events/BaseEvent.java index 723a9c69fbd5..a4e04154fd24 100644 --- a/src/main/java/seedu/address/commons/events/BaseEvent.java +++ b/src/main/java/seedu/malitio/commons/events/BaseEvent.java @@ -1,4 +1,4 @@ -package seedu.address.commons.events; +package seedu.malitio.commons.events; public abstract class BaseEvent { diff --git a/src/main/java/seedu/malitio/commons/events/model/MalitioChangedEvent.java b/src/main/java/seedu/malitio/commons/events/model/MalitioChangedEvent.java new file mode 100644 index 000000000000..206d61c64803 --- /dev/null +++ b/src/main/java/seedu/malitio/commons/events/model/MalitioChangedEvent.java @@ -0,0 +1,25 @@ +package seedu.malitio.commons.events.model; + +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.model.ReadOnlyMalitio; + +/** Indicates the Malitio in the model has changed*/ +public class MalitioChangedEvent extends BaseEvent { + + public final ReadOnlyMalitio data; + + public MalitioChangedEvent(ReadOnlyMalitio data){ + this.data = data; + } + + @Override + public String toString() { + int totalSize = data.getFloatingTaskList().size() + + data.getDeadlineList().size() + + data.getEventList().size(); + + return "number of tasks " + + totalSize + + ", number of tags " + data.getTagList().size(); + } +} diff --git a/src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java b/src/main/java/seedu/malitio/commons/events/storage/DataSavingExceptionEvent.java similarity index 78% rename from src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java rename to src/main/java/seedu/malitio/commons/events/storage/DataSavingExceptionEvent.java index f0a0640ee523..83c2d7b67ed0 100644 --- a/src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java +++ b/src/main/java/seedu/malitio/commons/events/storage/DataSavingExceptionEvent.java @@ -1,6 +1,6 @@ -package seedu.address.commons.events.storage; +package seedu.malitio.commons.events.storage; -import seedu.address.commons.events.BaseEvent; +import seedu.malitio.commons.events.BaseEvent; /** * Indicates an exception during a file saving diff --git a/src/main/java/seedu/malitio/commons/events/storage/DataStorageFileChangedEvent.java b/src/main/java/seedu/malitio/commons/events/storage/DataStorageFileChangedEvent.java new file mode 100644 index 000000000000..f29ea91746be --- /dev/null +++ b/src/main/java/seedu/malitio/commons/events/storage/DataStorageFileChangedEvent.java @@ -0,0 +1,24 @@ +package seedu.malitio.commons.events.storage; + +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.model.UserPrefs; + +/** + * Indicates the storage file directory for Malitio data has changed + * + */ +//@@author a0126633j +public class DataStorageFileChangedEvent extends BaseEvent { + + public String dataFilePath; + + public DataStorageFileChangedEvent(String dataFilePath) { + this.dataFilePath = dataFilePath; + } + + @Override + public String toString() { + return "Directory of storage changed to " + dataFilePath; + } + +} diff --git a/src/main/java/seedu/malitio/commons/events/ui/DeadlinePanelSelectionChangedEvent.java b/src/main/java/seedu/malitio/commons/events/ui/DeadlinePanelSelectionChangedEvent.java new file mode 100644 index 000000000000..e78ed8e9f153 --- /dev/null +++ b/src/main/java/seedu/malitio/commons/events/ui/DeadlinePanelSelectionChangedEvent.java @@ -0,0 +1,24 @@ +package seedu.malitio.commons.events.ui; + +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.model.task.ReadOnlyDeadline; +//@@author A0129595N + +/** + * Represents a selection change in the Deadline List Panel + */ +public class DeadlinePanelSelectionChangedEvent extends BaseEvent{ + private ReadOnlyDeadline newDeadlineSelection; + + public DeadlinePanelSelectionChangedEvent(ReadOnlyDeadline newSelection) { + this.newDeadlineSelection = newSelection; + } + public ReadOnlyDeadline getNewDeadlineSelection() { + return newDeadlineSelection; + } + @Override + public String toString() { + return this.getClass().getSimpleName(); + } + +} diff --git a/src/main/java/seedu/malitio/commons/events/ui/EventPanelSelectionChangedEvent.java b/src/main/java/seedu/malitio/commons/events/ui/EventPanelSelectionChangedEvent.java new file mode 100644 index 000000000000..63ee8165dadb --- /dev/null +++ b/src/main/java/seedu/malitio/commons/events/ui/EventPanelSelectionChangedEvent.java @@ -0,0 +1,25 @@ +package seedu.malitio.commons.events.ui; + +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.model.task.ReadOnlyEvent; + +//@@author A0129595N +/** + * Represents a selection change in the Event List Panel + */ +public class EventPanelSelectionChangedEvent extends BaseEvent { + private ReadOnlyEvent newEventSelection; + + public EventPanelSelectionChangedEvent(ReadOnlyEvent newSelection) { + this.newEventSelection = newSelection; + } + + public ReadOnlyEvent getNewEventSelection() { + return newEventSelection; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java b/src/main/java/seedu/malitio/commons/events/ui/ExitAppRequestEvent.java similarity index 70% rename from src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java rename to src/main/java/seedu/malitio/commons/events/ui/ExitAppRequestEvent.java index 9af6194543a3..bc1e1adbf2d4 100644 --- a/src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java +++ b/src/main/java/seedu/malitio/commons/events/ui/ExitAppRequestEvent.java @@ -1,6 +1,6 @@ -package seedu.address.commons.events.ui; +package seedu.malitio.commons.events.ui; -import seedu.address.commons.events.BaseEvent; +import seedu.malitio.commons.events.BaseEvent; /** * Indicates a request for App termination diff --git a/src/main/java/seedu/address/commons/events/ui/IncorrectCommandAttemptedEvent.java b/src/main/java/seedu/malitio/commons/events/ui/IncorrectCommandAttemptedEvent.java similarity index 68% rename from src/main/java/seedu/address/commons/events/ui/IncorrectCommandAttemptedEvent.java rename to src/main/java/seedu/malitio/commons/events/ui/IncorrectCommandAttemptedEvent.java index 991f7ae9fa25..f4a3bc4869d1 100644 --- a/src/main/java/seedu/address/commons/events/ui/IncorrectCommandAttemptedEvent.java +++ b/src/main/java/seedu/malitio/commons/events/ui/IncorrectCommandAttemptedEvent.java @@ -1,7 +1,7 @@ -package seedu.address.commons.events.ui; +package seedu.malitio.commons.events.ui; -import seedu.address.commons.events.BaseEvent; -import seedu.address.logic.commands.Command; +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.logic.commands.Command; /** * Indicates an attempt to execute an incorrect command diff --git a/src/main/java/seedu/malitio/commons/events/ui/JumpToListRequestEvent.java b/src/main/java/seedu/malitio/commons/events/ui/JumpToListRequestEvent.java new file mode 100644 index 000000000000..c84bc8f41eaa --- /dev/null +++ b/src/main/java/seedu/malitio/commons/events/ui/JumpToListRequestEvent.java @@ -0,0 +1,19 @@ +package seedu.malitio.commons.events.ui; + +import seedu.malitio.commons.events.BaseEvent; +//@@author A0129595N +public class JumpToListRequestEvent extends BaseEvent{ + + public final int targetIndex; + public final String typeOfTask; + + public JumpToListRequestEvent(int targetIndex, String typeOfTask) { + this.targetIndex = targetIndex; + this.typeOfTask = typeOfTask; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java b/src/main/java/seedu/malitio/commons/events/ui/ShowHelpRequestEvent.java similarity index 70% rename from src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java rename to src/main/java/seedu/malitio/commons/events/ui/ShowHelpRequestEvent.java index a7e40940b2c7..52909c3d38e4 100644 --- a/src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java +++ b/src/main/java/seedu/malitio/commons/events/ui/ShowHelpRequestEvent.java @@ -1,6 +1,6 @@ -package seedu.address.commons.events.ui; +package seedu.malitio.commons.events.ui; -import seedu.address.commons.events.BaseEvent; +import seedu.malitio.commons.events.BaseEvent; /** * An event requesting to view the help page. diff --git a/src/main/java/seedu/malitio/commons/events/ui/TaskPanelSelectionChangedEvent.java b/src/main/java/seedu/malitio/commons/events/ui/TaskPanelSelectionChangedEvent.java new file mode 100644 index 000000000000..17a6dc007733 --- /dev/null +++ b/src/main/java/seedu/malitio/commons/events/ui/TaskPanelSelectionChangedEvent.java @@ -0,0 +1,28 @@ +package seedu.malitio.commons.events.ui; + +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +//@@author A0129595N +/** + * Represents a selection change in the FloatingTask List Panel + */ +public class TaskPanelSelectionChangedEvent extends BaseEvent { + + + private ReadOnlyFloatingTask newTaskSelection; + + public TaskPanelSelectionChangedEvent(ReadOnlyFloatingTask newSelection) { + this.newTaskSelection = newSelection; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } + + public ReadOnlyFloatingTask getNewFloatingTaskSelection() { + return newTaskSelection; + } + +} diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/malitio/commons/exceptions/DataConversionException.java similarity index 84% rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java rename to src/main/java/seedu/malitio/commons/exceptions/DataConversionException.java index 1f689bd8e3f9..3980ce5c01da 100644 --- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java +++ b/src/main/java/seedu/malitio/commons/exceptions/DataConversionException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.malitio.commons.exceptions; /** * Represents an error during conversion of data from one format to another diff --git a/src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java b/src/main/java/seedu/malitio/commons/exceptions/DuplicateDataException.java similarity index 85% rename from src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java rename to src/main/java/seedu/malitio/commons/exceptions/DuplicateDataException.java index 17aa63d5020c..f3f3e82044cd 100644 --- a/src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java +++ b/src/main/java/seedu/malitio/commons/exceptions/DuplicateDataException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.malitio.commons.exceptions; /** * Signals an error caused by duplicate data where there should be none. diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/malitio/commons/exceptions/IllegalValueException.java similarity index 88% rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java rename to src/main/java/seedu/malitio/commons/exceptions/IllegalValueException.java index a473b43bd86f..0dd4fe34094d 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/seedu/malitio/commons/exceptions/IllegalValueException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.malitio.commons.exceptions; /** * Signals that some given data does not fulfill some constraints. diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/malitio/commons/util/AppUtil.java similarity index 81% rename from src/main/java/seedu/address/commons/util/AppUtil.java rename to src/main/java/seedu/malitio/commons/util/AppUtil.java index 649cc19aaeda..02136133424e 100644 --- a/src/main/java/seedu/address/commons/util/AppUtil.java +++ b/src/main/java/seedu/malitio/commons/util/AppUtil.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import javafx.scene.image.Image; -import seedu.address.MainApp; +import seedu.malitio.MainApp; /** * A container for App specific utility functions diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/malitio/commons/util/CollectionUtil.java similarity index 96% rename from src/main/java/seedu/address/commons/util/CollectionUtil.java rename to src/main/java/seedu/malitio/commons/util/CollectionUtil.java index fde8394f31e5..06c4d1e08ebb 100644 --- a/src/main/java/seedu/address/commons/util/CollectionUtil.java +++ b/src/main/java/seedu/malitio/commons/util/CollectionUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import java.util.Collection; import java.util.HashSet; diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/malitio/commons/util/ConfigUtil.java similarity index 64% rename from src/main/java/seedu/address/commons/util/ConfigUtil.java rename to src/main/java/seedu/malitio/commons/util/ConfigUtil.java index af42e03df06c..f59ccb6da2bb 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/seedu/malitio/commons/util/ConfigUtil.java @@ -1,8 +1,8 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.exceptions.DataConversionException; import java.io.File; import java.io.IOException; @@ -58,5 +58,29 @@ public static void saveConfig(Config config, String configFilePath) throws IOExc FileUtil.serializeObjectToJsonFile(new File(configFilePath), config); } + + /** + * Changing the location of saving local data in config.json file + * @param dataFilePath + */ + //@@author a0126633j + public static void changeMalitioSaveDirectory(String dataFilePath) { + Config existingConfig; + + try { + Optional config = readConfig(Config.DEFAULT_CONFIG_FILE); + existingConfig = config.orElse(new Config()); + } catch (DataConversionException e) { + logger.warning("Could not find existing Config file. Created a new Config file."); + existingConfig = new Config(); + } + + existingConfig.setMalitioFilePath(dataFilePath); + try { + saveConfig(existingConfig, Config.DEFAULT_CONFIG_FILE); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + } } diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/malitio/commons/util/FileUtil.java similarity index 78% rename from src/main/java/seedu/address/commons/util/FileUtil.java rename to src/main/java/seedu/malitio/commons/util/FileUtil.java index ca8221250de4..dfc391bd3661 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/seedu/malitio/commons/util/FileUtil.java @@ -1,8 +1,10 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; /** * Writes and reads file @@ -92,4 +94,25 @@ public static T deserializeObjectFromJsonFile(File jsonFile, Class classO throws IOException { return JsonUtil.fromJsonString(FileUtil.readFromFile(jsonFile), classOfObjectToDeserialize); } + + //@@author a0126633j + public static void deleteFile(String filePath) throws IOException { + Path path = Paths.get(filePath); + Files.deleteIfExists(path); + } + + /** + * + * Converts two strings of file path to their canonical values and then compares them. + */ + public static boolean twoFilePathsAreEqual(String filePath1, String filePath2) throws IOException { + try { + if (new File(filePath1).getCanonicalPath().compareTo(new File(filePath2).getCanonicalPath()) == 0) { + return true; + } + } catch (IOException e1) { + throw new IOException("Fail to compare two file paths"); + } + return false; + } } diff --git a/src/main/java/seedu/address/commons/util/FxViewUtil.java b/src/main/java/seedu/malitio/commons/util/FxViewUtil.java similarity index 92% rename from src/main/java/seedu/address/commons/util/FxViewUtil.java rename to src/main/java/seedu/malitio/commons/util/FxViewUtil.java index 900efa6bf5c3..e4c7a4950350 100644 --- a/src/main/java/seedu/address/commons/util/FxViewUtil.java +++ b/src/main/java/seedu/malitio/commons/util/FxViewUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import javafx.scene.Node; import javafx.scene.layout.AnchorPane; diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/malitio/commons/util/JsonUtil.java similarity index 98% rename from src/main/java/seedu/address/commons/util/JsonUtil.java rename to src/main/java/seedu/malitio/commons/util/JsonUtil.java index 80b67de5b7e8..47492725717e 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/seedu/malitio/commons/util/JsonUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; diff --git a/src/main/java/seedu/malitio/commons/util/StringUtil.java b/src/main/java/seedu/malitio/commons/util/StringUtil.java new file mode 100644 index 000000000000..dab6536adebf --- /dev/null +++ b/src/main/java/seedu/malitio/commons/util/StringUtil.java @@ -0,0 +1,72 @@ +package seedu.malitio.commons.util; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.List; + +/** + * Helper functions for handling strings. + */ +public class StringUtil { + + //@@author a0126633j + /** + * Checks whether any of the query is part of the source string. + */ + public static boolean containsIgnoreCase(String source, String query) { + String[] splitSource = source.toLowerCase().split("\\s+"); + String[] splitQuery = query.toLowerCase().split("\\s+"); + + for(int i = 0; i < splitQuery.length; i++) { + for(int j = 0; j < splitSource.length; j++) { + if (splitSource[j].contains(splitQuery[i])) { + return true; + } + } + } + return false; + } + //@@author + + /** + * Returns a detailed message of the t, including the stack trace. + */ + public static String getDetails(Throwable t){ + assert t != null; + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + return t.getMessage() + "\n" + sw.toString(); + } + + /** + * Returns true if s represents an unsigned integer e.g. 1, 2, 3, ...
+ * Will return false for null, empty string, "-1", "0", "+1", and " 2 " (untrimmed) "3 0" (contains whitespace). + * @param s Should be trimmed. + */ + public static boolean isUnsignedInteger(String s){ + return s != null && s.matches("^0*[1-9]\\d*$"); + } + + /** + * Removes the tag arguments in a string + * @return + */ + public static String removeTagsFromString(String arg) { + // string has no tags to begin with + if(arg.indexOf("t/") == -1) { + return arg; + } + + return arg.substring(0,arg.indexOf("t/")); + } + + //@@author a0126633j + /** + * Reformats a tag string into a string separated by white space. + * e.g. "[cs2103], [cs1010e]" into "cs2103 cs1010e". + */ + public static String reformatTagString(String arg) { + return arg.replaceAll(",", "").replaceAll("\\[|\\]", " "); + } +} diff --git a/src/main/java/seedu/address/commons/util/UrlUtil.java b/src/main/java/seedu/malitio/commons/util/UrlUtil.java similarity index 94% rename from src/main/java/seedu/address/commons/util/UrlUtil.java rename to src/main/java/seedu/malitio/commons/util/UrlUtil.java index 6bbab52b9840..f7650cd5bf5e 100644 --- a/src/main/java/seedu/address/commons/util/UrlUtil.java +++ b/src/main/java/seedu/malitio/commons/util/UrlUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import java.net.URL; diff --git a/src/main/java/seedu/address/commons/util/XmlUtil.java b/src/main/java/seedu/malitio/commons/util/XmlUtil.java similarity index 98% rename from src/main/java/seedu/address/commons/util/XmlUtil.java rename to src/main/java/seedu/malitio/commons/util/XmlUtil.java index 2087e7628a1d..763ec2aee929 100644 --- a/src/main/java/seedu/address/commons/util/XmlUtil.java +++ b/src/main/java/seedu/malitio/commons/util/XmlUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; diff --git a/src/main/java/seedu/malitio/logic/Logic.java b/src/main/java/seedu/malitio/logic/Logic.java new file mode 100644 index 000000000000..a14324905872 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/Logic.java @@ -0,0 +1,29 @@ +package seedu.malitio.logic; + +import javafx.collections.ObservableList; +import seedu.malitio.logic.commands.CommandResult; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +/** + * API of the Logic component + */ +public interface Logic { + /** + * Executes the command and returns the result. + * @param commandText The command as entered by the user. + * @return the result of the command execution. + */ + CommandResult execute(String commandText); + + //@@ Annabel Eng A0129595N + /** Returns the filtered list of tasks */ + ObservableList getFilteredFloatingTaskList(); + + ObservableList getFilteredDeadlineList(); + + ObservableList getFilteredEventList(); + + +} diff --git a/src/main/java/seedu/malitio/logic/LogicManager.java b/src/main/java/seedu/malitio/logic/LogicManager.java new file mode 100644 index 000000000000..c96f7960d050 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/LogicManager.java @@ -0,0 +1,53 @@ +package seedu.malitio.logic; + +import javafx.collections.ObservableList; +import seedu.malitio.commons.core.ComponentManager; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.logic.commands.Command; +import seedu.malitio.logic.commands.CommandResult; +import seedu.malitio.logic.parser.Parser; +import seedu.malitio.model.Model; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.storage.Storage; + +import java.util.logging.Logger; + +/** + * The main LogicManager of the app. + */ +public class LogicManager extends ComponentManager implements Logic { + private final Logger logger = LogsCenter.getLogger(LogicManager.class); + + private final Model model; + private final Parser parser; + + public LogicManager(Model model, Storage storage) { + this.model = model; + this.parser = new Parser(); + } + + @Override + public CommandResult execute(String commandText) { + logger.info("----------------[USER COMMAND][" + commandText + "]"); + Command command = parser.parseCommand(commandText); + command.setData(model); + return command.execute(); + } + + @Override + public ObservableList getFilteredFloatingTaskList() { + return model.getFilteredFloatingTaskList(); + } + + @Override + public ObservableList getFilteredDeadlineList() { + return model.getFilteredDeadlineList(); + } + + @Override + public ObservableList getFilteredEventList() { + return model.getFilteredEventList(); + } +} diff --git a/src/main/java/seedu/malitio/logic/commands/AddCommand.java b/src/main/java/seedu/malitio/logic/commands/AddCommand.java new file mode 100644 index 000000000000..daa1b940e022 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/AddCommand.java @@ -0,0 +1,108 @@ +package seedu.malitio.logic.commands; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; +import seedu.malitio.model.task.UniqueDeadlineList.DuplicateDeadlineException; +import seedu.malitio.model.task.UniqueEventList.DuplicateEventException; +import seedu.malitio.model.task.UniqueFloatingTaskList.DuplicateFloatingTaskException; + +import java.util.HashSet; +import java.util.Set; +//@@author A0129595N +/** + * Adds a task to Malitio. + */ +public class AddCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": adds a task to Malitio. Task name cannot contain \'/\'. \n" + + "Parameters: NAME [by DEADLINE] [start STARTTIME end ENDTIME] [t/TAG]...\n" + + "Example: " + COMMAND_WORD + + " Pay John $100 by Oct 11 2359 t/oweMoney"; + + public static final String MESSAGE_SUCCESS = "New task added %1$s"; + public static final String MESSAGE_DUPLICATE_TASK = "This floating task already exists in Malitio"; + public static final String MESSAGE_DUPLICATE_EVENT = "This event already exists in Malitio"; + public static final String MESSAGE_DUPLICATE_DEADLINE ="This deadline already exists in Malitio"; + + private Object toAddTask; + + /** + * Convenience constructor for floating tasks using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAddTask = new FloatingTask( + new Name(name), + new UniqueTagList(tagSet) + ); + } + + /** + * Convenience constructor for deadlines using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + + public AddCommand(String name, String date, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAddTask = new Deadline( + new Name(name), + new DateTime(date), + new UniqueTagList(tagSet) + ); + } + + /** + * Convenience constructor for events using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, String start, String end, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + // check if start < end + this.toAddTask = new Event( + new Name(name), + new DateTime(start), + new DateTime(end), + new UniqueTagList(tagSet) + ); + } + + /** + * Executes the command. It will clear the future stack so that no redo can be done after execution. + */ + @Override + public CommandResult execute() { + assert model != null;{ + try { + model.addTask(toAddTask); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAddTask)); + } catch (DuplicateFloatingTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } catch (DuplicateDeadlineException e) { + return new CommandResult(MESSAGE_DUPLICATE_DEADLINE); + } catch (DuplicateEventException e) { + return new CommandResult(MESSAGE_DUPLICATE_EVENT); + } + } + } +} diff --git a/src/main/java/seedu/malitio/logic/commands/ClearCommand.java b/src/main/java/seedu/malitio/logic/commands/ClearCommand.java new file mode 100644 index 000000000000..6e06c42ca980 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/ClearCommand.java @@ -0,0 +1,49 @@ +package seedu.malitio.logic.commands; + +import java.util.Arrays; + +import seedu.malitio.model.Malitio; + +//@@author a0126633j +/** + * Clears the malitio partially or fully. + */ +public class ClearCommand extends Command { + + public static final String[] VALID_ARGUMENTS = {"", "expired" }; + + public static final String COMMAND_WORD = "clear"; + public static final String MESSAGE_SUCCESS = "Malitio has been cleared!"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes multiple tasks at once.\n" + + "Parameters: none OR " + VALID_ARGUMENTS[1] +"\n" + + "Example: clear" + VALID_ARGUMENTS[0] + + ", clear " + VALID_ARGUMENTS[1]; + + private String arg; + + public ClearCommand(String arg) { + this.arg = arg; + } + + @Override + public CommandResult execute() { + assert model != null; + model.getFuture().clear(); + + int index = Arrays.asList(VALID_ARGUMENTS).indexOf(arg); + switch (index) { + case 0: + model.resetData(Malitio.getEmptymalitio()); + break; + + case 1: + model.clearExpiredTasks(); + break; + + default: + assert(false); //impossible as check is done at parsing + } + + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/malitio/logic/commands/Command.java similarity index 67% rename from src/main/java/seedu/address/logic/commands/Command.java rename to src/main/java/seedu/malitio/logic/commands/Command.java index 7c0ba2fd0161..5ab54a5ef83d 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/seedu/malitio/logic/commands/Command.java @@ -1,9 +1,9 @@ -package seedu.address.logic.commands; +package seedu.malitio.logic.commands; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.core.Messages; -import seedu.address.commons.events.ui.IncorrectCommandAttemptedEvent; -import seedu.address.model.Model; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.events.ui.IncorrectCommandAttemptedEvent; +import seedu.malitio.model.Model; /** * Represents a command with hidden internal logic and the ability to be executed. @@ -12,13 +12,13 @@ public abstract class Command { protected Model model; /** - * Constructs a feedback message to summarise an operation that displayed a listing of persons. + * Constructs a feedback message to summarise an operation that displayed a listing of tasks. * * @param displaySize used to generate summary - * @return summary message for persons displayed + * @return summary message for tasks displayed */ - public static String getMessageForPersonListShownSummary(int displaySize) { - return String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, displaySize); + public static String getMessageForTaskListShownSummary(int displaySize) { + return String.format(Messages.MESSAGE_TASKS_LISTED_OVERVIEW, displaySize); } /** diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/malitio/logic/commands/CommandResult.java similarity index 87% rename from src/main/java/seedu/address/logic/commands/CommandResult.java rename to src/main/java/seedu/malitio/logic/commands/CommandResult.java index f46f2f31353e..2a7b1cd0b271 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/malitio/logic/commands/CommandResult.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package seedu.malitio.logic.commands; /** * Represents the result of a command execution. diff --git a/src/main/java/seedu/malitio/logic/commands/CompleteCommand.java b/src/main/java/seedu/malitio/logic/commands/CompleteCommand.java new file mode 100644 index 000000000000..6e8b3a9bbd1b --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/CompleteCommand.java @@ -0,0 +1,106 @@ +package seedu.malitio.logic.commands; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.commons.exceptions.IllegalValueException; + +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineCompletedException; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineNotFoundException; +import seedu.malitio.model.task.UniqueFloatingTaskList; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskCompletedException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; + +//@@author A0122460W +/** + * Complete a floating task/ deadline identified using it's last displayed index + * from Malitio. strikeout the completed floating task/ deadline + * + */ +public class CompleteCommand extends Command { + + public static final String COMMAND_WORD = "complete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": complete the task or deadline identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d' and a positive integer) " + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_COMPLETED_TASK = "The floating task is already completed in Malitio"; + + public static final String MESSAGE_COMPLETED_DEADLINE = "The deadline is already completed in Malitio"; + + public static final String MESSAGE_COMPLETED_TASK_SUCCESS = "Successfully completed floating task."; + + public static final String MESSAGE_COMPLETED_DEADLINE_SUCCESS = "Successfully completed deadline."; + + private final char taskType; + + private final int targetIndex; + + public CompleteCommand(char taskType, int targetIndex) throws IllegalValueException { + assert taskType == 'd' || taskType == 'f'; + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + CommandResult result; + if (taskType == 'f') { + result = executeCompleteFloatingTask(); + model.getFuture().clear(); + return result; + } else { + result = executeCompleteDeadline(); + model.getFuture().clear(); + return result; + } + } + + private CommandResult executeCompleteFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToComplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.completeTask(taskToComplete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } catch (UniqueFloatingTaskList.FloatingTaskCompletedException e) { + return new CommandResult(MESSAGE_COMPLETED_TASK); + } catch (DeadlineCompletedException e) { + } catch (DeadlineNotFoundException e) { + } + return new CommandResult(String.format(MESSAGE_COMPLETED_TASK_SUCCESS, taskToComplete)); + } + + private CommandResult executeCompleteDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToComplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.completeTask(deadlineToComplete); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } catch (UniqueDeadlineList.DeadlineCompletedException e) { + return new CommandResult(MESSAGE_COMPLETED_DEADLINE); + } catch (FloatingTaskCompletedException e) { + } catch (FloatingTaskNotFoundException e) { + } + return new CommandResult(String.format(MESSAGE_COMPLETED_DEADLINE_SUCCESS, deadlineToComplete)); + } + +} diff --git a/src/main/java/seedu/malitio/logic/commands/DeleteCommand.java b/src/main/java/seedu/malitio/logic/commands/DeleteCommand.java new file mode 100644 index 000000000000..f5b29c9c4d49 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/DeleteCommand.java @@ -0,0 +1,105 @@ +package seedu.malitio.logic.commands; + +import java.util.Arrays; +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineNotFoundException; +import seedu.malitio.model.task.UniqueEventList.EventNotFoundException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; + +/** + * Deletes a task identified using it's last displayed index from Malitio. + * + */ +public class DeleteCommand extends Command { + + //@@author a0126633j + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the task identified by the index used in the last task listing.\n" + + "Parameters: INDEX \n" + "Example: " + COMMAND_WORD + " D1"; + + public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted %1$s"; + + private static final String[] TYPES_OF_TASKS = {"f","d", "e"}; + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + private static final int MINIMUM_INDEX_IN_LIST = 1; + + private final int targetIndex; + private final String taskType; + + public DeleteCommand(String taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + + assert(Arrays.asList(TYPES_OF_TASKS).contains(taskType)); + + int sizeOfList = 0; + + switch (taskType) { + case FLOATING_TASK_KEYWORD: + UnmodifiableObservableList lastShownFloatingTaskList = model.getFilteredFloatingTaskList(); + sizeOfList = lastShownFloatingTaskList.size(); + break; + case DEADLINE_KEYWORD: + UnmodifiableObservableList lastShownDeadlineList = model.getFilteredDeadlineList(); + sizeOfList = lastShownDeadlineList.size(); + break; + case EVENT_KEYWORD: + UnmodifiableObservableList lastShownEventList = model.getFilteredEventList(); + sizeOfList = lastShownEventList.size(); + } + + if (sizeOfList < targetIndex || targetIndex < MINIMUM_INDEX_IN_LIST) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + switch (taskType) { + case FLOATING_TASK_KEYWORD: + ReadOnlyFloatingTask taskToDelete = model.getFilteredFloatingTaskList().get(targetIndex - 1); + executeDelete(taskToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + + case DEADLINE_KEYWORD: + ReadOnlyDeadline deadlineToDelete = model.getFilteredDeadlineList().get(targetIndex - 1); + executeDelete(deadlineToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, deadlineToDelete)); + + default: + assert(taskType.equals(EVENT_KEYWORD)); + ReadOnlyEvent eventToDelete = model.getFilteredEventList().get(targetIndex - 1); + executeDelete(eventToDelete); + model.getFuture().clear(); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, eventToDelete)); + } + } + + /** + * Deletes a task from the model + */ + private void executeDelete(Object taskToDelete) { + try { + model.deleteTask(taskToDelete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target floating task cannot be missing"; + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (EventNotFoundException e) { + assert false : "The target event cannot be missing"; + } + } +} \ No newline at end of file diff --git a/src/main/java/seedu/malitio/logic/commands/EditCommand.java b/src/main/java/seedu/malitio/logic/commands/EditCommand.java new file mode 100644 index 000000000000..0346219f4c1e --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/EditCommand.java @@ -0,0 +1,279 @@ +package seedu.malitio.logic.commands; + +import java.util.HashSet; +import java.util.Set; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.DateTime; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.Event; +import seedu.malitio.model.task.FloatingTask; +import seedu.malitio.model.task.Name; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineNotFoundException; +import seedu.malitio.model.task.UniqueEventList.DuplicateEventException; +import seedu.malitio.model.task.UniqueEventList.EventNotFoundException; +import seedu.malitio.model.task.UniqueFloatingTaskList; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; +//@@author A0129595N +/** + * Edits a floating task/ deadline/ event identified using it's last displayed index from Malitio. + * Only the attribute(s) that require changes is(are) entered. + */ +public class EditCommand extends Command{ + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ":Edits the task identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d'/'e' and a positive integer) [NAME] [by NEWDATE] [START NEWDATE] [END NEWDATE]\n" + + "Example: " + COMMAND_WORD + " f1 New Name"; + + public static final String MESSAGE_DUPLICATE_TASK = "The intended edit correspond to a pre-existing floating task in Malitio"; + + public static final String MESSAGE_DUPLICATE_DEADLINE = "The intended edit correspond to a pre-existing deadline in Malitio"; + + public static final String MESSAGE_DUPLICATE_EVENT = "The intended edit correspond to a pre-existing event in Malitio"; + + public static final String MESSAGE_INVALID_EVENT = "Event must start before it ends!"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Successfully edited task.\nOld: %1$s\nNew: %2$s"; + + public static final String MESSAGE_CHANGING_TASK_TYPE_NOT_SUPPORTED = "Changing of task type not supported. Please do not use key words (by, start, end) in names."; + + private final char taskType; + + private final int targetIndex; + + private Object editedTask; + + private Object taskToEdit; + + private Name name; + + private DateTime due; + + private DateTime start; + + private DateTime end; + + private UniqueTagList tags; + + /** + * Process arguments by extracting out relevant details to change + */ + public EditCommand(char taskType, int targetIndex, String name, String due, String start, String end, Set newTags) + throws IllegalValueException { + assert validArgTask(taskType, name, due, start, end, newTags) ; + this.taskType = taskType; + this.targetIndex = targetIndex; + if (!name.equals("")) { + this.name = new Name(name); + } + if (!due.equals("")) { + this.due = new DateTime(due); + } + if (!start.equals("")) { + this.start = new DateTime(start); + } + if (!end.equals("")) { + this.end = new DateTime(end); + } + this.tags = processTags(newTags); + } + + /** + * Executes the command. It will clear the future stack so that no redo can be done after execution. + */ + @Override + public CommandResult execute() { + UnmodifiableObservableList lastShownList; + lastShownList = getCorrectList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + if (!detectWrongParameters()) { + return new CommandResult(MESSAGE_CHANGING_TASK_TYPE_NOT_SUPPORTED); + } + + taskToEdit = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + fillInTheGaps(taskToEdit); + constructEditedTask(); + model.editTask(editedTask, taskToEdit); + model.getFuture().clear(); + } catch (UniqueFloatingTaskList.DuplicateFloatingTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } catch (UniqueDeadlineList.DuplicateDeadlineException e) { + return new CommandResult(MESSAGE_DUPLICATE_DEADLINE); + } catch (DuplicateEventException e) { + return new CommandResult(MESSAGE_DUPLICATE_EVENT); + } catch (IllegalValueException e) { + return new CommandResult(MESSAGE_INVALID_EVENT); + } catch (FloatingTaskNotFoundException | DeadlineNotFoundException | EventNotFoundException e) { + assert false : "not possible"; + } + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit, editedTask)); + } + + private boolean detectWrongParameters() { + if ((taskType == 'f' && due == null && start == null && end == null)) { + return true; + } else if ((taskType == 'd' && start == null && end == null)) { + return true; + } else if ((taskType == 'e' && due == null)) { + return true; + } else { + return false; + } + } + + /** + * Creates the correct edited task object + * @throws IllegalValueException + */ + private void constructEditedTask() throws IllegalValueException { + if (taskType == 'f') { + editedTask = new FloatingTask(name, tags); + } else if (taskType == 'd') { + editedTask = new Deadline(name, due, tags); + } else { + editedTask = new Event(name, start, end, tags); + } + } + + /** + * @return UnmodifiableObservableList of the correct task type + */ + private UnmodifiableObservableList getCorrectList() { + UnmodifiableObservableList lastShownList; + if (taskType == 'f') { + lastShownList = model.getFilteredFloatingTaskList(); + } else if (taskType == 'd') { + lastShownList = model.getFilteredDeadlineList(); + } else { + lastShownList = model.getFilteredEventList(); + } + return lastShownList; + } + + + /** + * fillInTheGaps will replace the task's attributes not entered by the user by extracting from the task to be edited . + * @param ReadOnly + */ + private void fillInTheGaps(Object taskToEdit) { + if (isFloatingTask(taskToEdit)) { + getFloatingTaskDetails(taskToEdit); + } else if (isDeadline(taskToEdit)) { + getDeadlineDetails(taskToEdit); + } else { + getEventDetails(taskToEdit); + } + } + + /** + * Method to check for valid (at least one non-empty) arguments for the corresponding task type + */ + private boolean validArgTask(char taskType, String name, String due, String start, String end, + Set newTags) { + if (taskType == 'f') { + return (!name.equals("") || !newTags.isEmpty()) && start.equals("") && end.equals("") && due.equals(""); + } else if (taskType == 'd') { + return (!name.equals("") || !due.equals("") || !newTags.isEmpty()) && start.equals("") + && end.equals(""); + } else { + return (!name.equals("") || !start.equals("") || !end.equals("") || !newTags.isEmpty()) + && due.equals(""); + } + } + + private boolean isDeadline(Object taskToEdit) { + return taskToEdit instanceof ReadOnlyDeadline; + } + + private boolean isFloatingTask(Object taskToEdit) { + return taskToEdit instanceof ReadOnlyFloatingTask; + } + + /** + * processTags return a UniqueTagList of tags or returns null if no tags were entered. + * @param newTags + * @return UniqueTagList or Null + * @throws IllegalValueException + */ + private UniqueTagList processTags(Set newTags) throws IllegalValueException { + if (!newTags.isEmpty() && newTags.toArray()[0].equals("null") && newTags.size()==1) { + return new UniqueTagList(); + } + else if (!newTags.isEmpty()){ + final Set tagSet = new HashSet<>(); + for (String tagName : newTags) { + tagSet.add(new Tag(tagName)); + } + return new UniqueTagList(tagSet); + } + else { + return null; + } + } + + /** + * Replace the editedTask, type casted to Event, details if they are empty + * @param taskToEdit + */ + private void getEventDetails(Object taskToEdit) { + if (this.name == null) { + this.name = ((Event) taskToEdit).getName(); + } + if (this.start == null) { + this.start = ((Event) taskToEdit).getStart(); + } + if (this.end == null) { + this.end = ((Event) taskToEdit).getEnd(); + } + if (this.tags == null) { + this.tags = ((Event) taskToEdit).getTags(); + } + } + + /** + * Replace the editedTask, type casted to Deadline, details if they are empty + * @param taskToEdit + */ + private void getDeadlineDetails(Object taskToEdit) { + if (this.name == null) { + this.name = ((ReadOnlyDeadline) taskToEdit).getName(); + } + if (this.due == null) { + this.due = ((ReadOnlyDeadline) taskToEdit).getDue(); + } + if (this.tags == null) { + this.tags = ((ReadOnlyDeadline) taskToEdit).getTags(); + } + } + + /** + * Replace the editedTask, type casted to Floating Task, details if they are empty + * @param taskToEdit + */ + private void getFloatingTaskDetails(Object taskToEdit) { + if (this.name == null) { + this.name = ((ReadOnlyFloatingTask) taskToEdit).getName(); + } + if (this.tags == null) { + this.tags = ((ReadOnlyFloatingTask) taskToEdit).getTags(); + } + } + +} diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/malitio/logic/commands/ExitCommand.java similarity index 69% rename from src/main/java/seedu/address/logic/commands/ExitCommand.java rename to src/main/java/seedu/malitio/logic/commands/ExitCommand.java index d98233ce2a0b..a7066c3c4f5a 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/seedu/malitio/logic/commands/ExitCommand.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands; +package seedu.malitio.logic.commands; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.ui.ExitAppRequestEvent; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.events.ui.ExitAppRequestEvent; /** * Terminates the program. @@ -10,7 +10,7 @@ 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 static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Malitio as requested ..."; public ExitCommand() {} diff --git a/src/main/java/seedu/malitio/logic/commands/FindCommand.java b/src/main/java/seedu/malitio/logic/commands/FindCommand.java new file mode 100644 index 000000000000..d80e90cc0258 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/FindCommand.java @@ -0,0 +1,55 @@ +package seedu.malitio.logic.commands; + +import java.util.Set; + +/** + * Finds and lists tasks from the last shown list whose name or tags or date/time contains any of the argument keywords. + * Keyword matching is case insensitive. + */ +public class FindCommand extends Command { + //@@author a0126633j + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds [specified] tasks whose names contain any of " + + "the specified keywords and displays them as a list with index numbers.\n" + + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " [f/d/e] adjust bring chill"; + + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + + private final Set keywords; + private final String typeOfTask; + + public FindCommand(String type, Set keywords) { + this.keywords = keywords; + this.typeOfTask = type; + } + + @Override + public CommandResult execute() { + + switch (typeOfTask) { + case FLOATING_TASK_KEYWORD: + model.updateFilteredTaskList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredFloatingTaskList().size())); + case DEADLINE_KEYWORD: + model.updateFilteredDeadlineList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredDeadlineList().size())); + case EVENT_KEYWORD: + model.updateFilteredEventList(keywords); + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredEventList().size())); + + default: //find in all lists + model.updateFilteredTaskList(keywords); + model.updateFilteredDeadlineList(keywords); + model.updateFilteredEventList(keywords); + return new CommandResult(getMessageForTaskListShownSummary( + model.getFilteredFloatingTaskList().size() + + model.getFilteredDeadlineList().size() + + model.getFilteredEventList().size())); + } + } + +} diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/malitio/logic/commands/HelpCommand.java similarity index 80% rename from src/main/java/seedu/address/logic/commands/HelpCommand.java rename to src/main/java/seedu/malitio/logic/commands/HelpCommand.java index 65af96940242..d22153c4f640 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/seedu/malitio/logic/commands/HelpCommand.java @@ -1,8 +1,8 @@ -package seedu.address.logic.commands; +package seedu.malitio.logic.commands; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.ui.ShowHelpRequestEvent; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.events.ui.ShowHelpRequestEvent; /** * Format full help instructions for every command for display. diff --git a/src/main/java/seedu/address/logic/commands/IncorrectCommand.java b/src/main/java/seedu/malitio/logic/commands/IncorrectCommand.java similarity index 92% rename from src/main/java/seedu/address/logic/commands/IncorrectCommand.java rename to src/main/java/seedu/malitio/logic/commands/IncorrectCommand.java index 491d9cb9da35..0604608bb8ac 100644 --- a/src/main/java/seedu/address/logic/commands/IncorrectCommand.java +++ b/src/main/java/seedu/malitio/logic/commands/IncorrectCommand.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package seedu.malitio.logic.commands; /** diff --git a/src/main/java/seedu/malitio/logic/commands/ListAllCommand.java b/src/main/java/seedu/malitio/logic/commands/ListAllCommand.java new file mode 100644 index 000000000000..f93903f4deb3 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/ListAllCommand.java @@ -0,0 +1,26 @@ +package seedu.malitio.logic.commands; + +/** + * Lists all or specified tasks in Malitio to the user. + * @@author A0122460W + */ +public class ListAllCommand extends Command { + + public static final String COMMAND_WORD = "listall"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Lists all task in Malitio\n" + + "Parameters: listall\n" + + "Example: " + COMMAND_WORD; + + public static final String LISTALL_MESSAGE_SUCCESS = "Listed all tasks from beginning of time"; + + public ListAllCommand() {} + + + @Override + public CommandResult execute() { + model.ShowAllTask(); + return new CommandResult(LISTALL_MESSAGE_SUCCESS); + + } +} diff --git a/src/main/java/seedu/malitio/logic/commands/ListCommand.java b/src/main/java/seedu/malitio/logic/commands/ListCommand.java new file mode 100644 index 000000000000..f309812a78ec --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/ListCommand.java @@ -0,0 +1,78 @@ +package seedu.malitio.logic.commands; + +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.task.*; + +/** + * Lists all or specified tasks in Malitio to the user. + * @@author A0153006W + */ +public class ListCommand extends Command { + + public static final String COMMAND_WORD = "list"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Lists specified type of task to Malitio\n" + + "Parameters: [events|deadlines|tasks] [DATETIME]\n" + + "Example: " + COMMAND_WORD + " deadlines " + "sunday midnight"; + + public static final String ALL_MESSAGE_SUCCESS = "Listed all tasks"; + public static final String TASK_MESSAGE_SUCCESS = "Listed floating tasks"; + public static final String DEADLINE_MESSAGE_SUCCESS = "Listed deadlines"; + public static final String EVENT_MESSAGE_SUCCESS = "Listed events"; + + private String taskType = ""; + private DateTime timeKeyWord = null; + + public ListCommand() {} + + public ListCommand(String args) throws IllegalValueException { + if (args.matches("(floating )?tasks?.*")) { + this.taskType = "tasks"; + return; + } + else if (args.matches("deadlines?.*")) { + this.taskType = "deadlines"; + args = args.replaceAll("deadlines?\\s*", ""); + } + else if (args.matches("events?.*")) { + this.taskType = "events"; + args = args.replaceAll("events?\\s*", ""); + } + if (!args.isEmpty()) { + timeKeyWord = new DateTime(args); + } + } + + @Override + public CommandResult execute() { + if (taskType.equals("tasks")) { + model.updateFilteredTaskListToShowAll(); + return new CommandResult(TASK_MESSAGE_SUCCESS); + } else if (taskType.equals("deadlines")) { + if (timeKeyWord != null) { + model.updateFilteredDeadlineList(timeKeyWord); + } else { + model.updateFilteredDeadlineListToShowAll(); + } + return new CommandResult(DEADLINE_MESSAGE_SUCCESS); + } else if (taskType.equals("events")) { + if (timeKeyWord != null) { + model.updateFilteredEventList(timeKeyWord); + } else { + model.updateFilteredEventListToShowAll(); + } + return new CommandResult(EVENT_MESSAGE_SUCCESS); + } else { + if (timeKeyWord != null) { + model.updateFilteredDeadlineList(timeKeyWord); + model.updateFilteredEventList(timeKeyWord); + } else { + model.updateFilteredTaskListToShowAll(); + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + } + return new CommandResult(ALL_MESSAGE_SUCCESS); + } + } +} diff --git a/src/main/java/seedu/malitio/logic/commands/MarkCommand.java b/src/main/java/seedu/malitio/logic/commands/MarkCommand.java new file mode 100644 index 000000000000..d50a2e1ce114 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/MarkCommand.java @@ -0,0 +1,85 @@ +package seedu.malitio.logic.commands; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineMarkedException; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineNotFoundException; +import seedu.malitio.model.task.UniqueEventList.EventMarkedException; +import seedu.malitio.model.task.UniqueEventList.EventNotFoundException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskMarkedException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; + +/** + * Marks a specified task or deadline as a priority in Malitio to the user. + * @@author A0153006W + */ +public class MarkCommand extends Command { + + public static final String COMMAND_WORD = "mark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Marks specified task or deadline as priority in Malitio\n" + + "Parameters: INDEX\n" + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_MARK_SUCCESS = "Task has been marked as priority"; + public static final String MESSAGE_MARK_AGAIN = "Task has already been marked as priority"; + + private final int targetIndex; + private final char taskType; + + private Object taskToMark; + + public MarkCommand(char taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + if (!(taskType == 'f' || taskType == 'd' || taskType == 'e')) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + UnmodifiableObservableList lastShownList; + lastShownList = getCorrectList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + taskToMark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.markTask(taskToMark); + } catch (FloatingTaskNotFoundException e) { + assert false : "The target floating task cannot be missing"; + } catch (FloatingTaskMarkedException e) { + return new CommandResult(MESSAGE_MARK_AGAIN); + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (DeadlineMarkedException e) { + return new CommandResult(MESSAGE_MARK_AGAIN); + } catch (EventNotFoundException e) { + assert false : "The target event cannot be missing"; + } catch (EventMarkedException e) { + return new CommandResult(MESSAGE_MARK_AGAIN); + } + return new CommandResult(MESSAGE_MARK_SUCCESS); + } + + /** + * @return UnmodifiableObservableList of the correct task type + */ + private UnmodifiableObservableList getCorrectList() { + UnmodifiableObservableList lastShownList; + if (taskType == 'f') { + lastShownList = model.getFilteredFloatingTaskList(); + } else if (taskType == 'd') { + lastShownList = model.getFilteredDeadlineList(); + } else { + lastShownList = model.getFilteredEventList(); + } + return lastShownList; + } +} \ No newline at end of file diff --git a/src/main/java/seedu/malitio/logic/commands/RedoCommand.java b/src/main/java/seedu/malitio/logic/commands/RedoCommand.java new file mode 100644 index 000000000000..48ae186019f0 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/RedoCommand.java @@ -0,0 +1,162 @@ +package seedu.malitio.logic.commands; + +import java.util.Stack; + +import seedu.malitio.model.Malitio; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.history.InputAddHistory; +import seedu.malitio.model.history.InputClearHistory; +import seedu.malitio.model.history.InputCompleteHistory; +import seedu.malitio.model.history.InputDeleteHistory; +import seedu.malitio.model.history.InputEditHistory; +import seedu.malitio.model.history.InputHistory; +import seedu.malitio.model.history.InputMarkHistory; +import seedu.malitio.model.history.InputUncompleteHistory; +import seedu.malitio.model.history.InputUnmarkHistory; + +//@@author A0129595N +public class RedoCommand extends Command { + + public static final String COMMAND_WORD = "redo"; + public static final String MESSAGE_REDO_ADD_SUCCESS = "Redo successful. Redo add %1$s"; + public static final String MESSAGE_REDO_DELETE_SUCCESS = "Redo Successful. Redo delete %1$s"; + public static final String MESSAGE_REDO_CLEAR_SUCCESS = "Redo clear successful"; + public static final String MESSAGE_REDO_EDIT_SUCCESS = "Redo successful. Redo edit from %1$s to %2$s"; + public static final String MESSAGE_REDO_MARK_SUCCESS = "Redo mark sucessful"; + public static final String MESSAGE_REDO_UNMARK_SUCCESS = "Redo unmark sucessful"; + public static final String MESSAGE_REDO_COMPLETE_SUCCESS = "Redo complete successful"; + public static final String MESSAGE_REDO_UNCOMPLETE_SUCCESS = "Redo uncomplete successful"; + public String result; + + @Override + public CommandResult execute() { + + Stack future = model.getFuture(); + if (future.isEmpty()) { + return new CommandResult("No action to redo!"); + } + InputHistory previous = future.pop(); + + switch (previous.getUndoCommand()) { + + case AddCommand.COMMAND_WORD: + result = executeAdd((InputDeleteHistory) previous); + return new CommandResult(result); + + case DeleteCommand.COMMAND_WORD: + result = executeDelete((InputAddHistory) previous); + return new CommandResult(result); + + case EditCommand.COMMAND_WORD: + result = executeEdit((InputEditHistory) previous); + return new CommandResult(result); + + case ClearCommand.COMMAND_WORD: + result = executeClear((InputClearHistory) previous); + return new CommandResult(result); + + case UnmarkCommand.COMMAND_WORD: + result = executeUnmark((InputMarkHistory) previous); + return new CommandResult(result); + + case MarkCommand.COMMAND_WORD: + result = executeMark((InputUnmarkHistory) previous); + return new CommandResult(result); + + case UncompleteCommand.COMMAND_WORD: + result = executeUncomplete((InputCompleteHistory) previous); + return new CommandResult(result); + + case CompleteCommand.COMMAND_WORD: + result = executeComplete((InputUncompleteHistory) previous); + return new CommandResult(result); + + default: + assert false; + return null; + } + } + + //========== Private helper methods ================================================== + + public String executeAdd(InputDeleteHistory previous) { + try { + if (isFloatingTask(previous)) { + model.addFloatingTaskAtSpecificPlace(previous.getTask(), previous.getPositionOfFloatingTask()); + } else { + model.addTask(previous.getTask()); + } + } catch (Exception e) { + assert false : "Not possible"; + } + return String.format(MESSAGE_REDO_ADD_SUCCESS, previous.getTask().toString()); + } + + public String executeDelete(InputAddHistory previous) { + try { + model.deleteTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return String.format(MESSAGE_REDO_DELETE_SUCCESS, previous.getTask().toString()); + } + + private String executeEdit(InputEditHistory previous) { + try { + model.editTask(previous.getEditedTask(), previous.getTaskToEdit()); + } catch (Exception e) { + assert false : "Not possible"; + } + return String.format(MESSAGE_REDO_EDIT_SUCCESS, previous.getTaskToEdit().toString(), previous.getEditedTask().toString()); + } + + private String executeClear(InputClearHistory previous) { + ReadOnlyMalitio previousModel = new Malitio(previous.getFloatingTask(), previous.getDeadline(), + previous.getEvent(), previous.getTag()); + model.resetData(previousModel); + return MESSAGE_REDO_CLEAR_SUCCESS; + } + + private String executeUnmark(InputMarkHistory previous) { + try { + model.unmarkTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_REDO_UNMARK_SUCCESS; + } + + private String executeMark(InputUnmarkHistory previous) { + try { + model.markTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_REDO_MARK_SUCCESS; + } + + private String executeUncomplete(InputCompleteHistory previous) { + try { + model.uncompleteTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_REDO_UNCOMPLETE_SUCCESS; + } + + private String executeComplete(InputUncompleteHistory previous) { + try { + model.completeTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_REDO_COMPLETE_SUCCESS; + } + + /** + * Method to check if the task is a floating task + */ + private boolean isFloatingTask(InputDeleteHistory previous) { + return previous.getPositionOfFloatingTask() != -1; + } +} diff --git a/src/main/java/seedu/malitio/logic/commands/SaveCommand.java b/src/main/java/seedu/malitio/logic/commands/SaveCommand.java new file mode 100644 index 000000000000..b48791d9287e --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/SaveCommand.java @@ -0,0 +1,84 @@ +package seedu.malitio.logic.commands; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Logger; + +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.storage.DataStorageFileChangedEvent; +import seedu.malitio.commons.util.ConfigUtil; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.commons.util.StringUtil; + +//@@author a0126633j +/** + * Allows the user to change the directory of save file. Old file in old directory will be deleted. + * The new directory will be remembered next time the App starts. + */ +public class SaveCommand extends Command { + + private static final Logger logger = LogsCenter.getLogger(SaveCommand.class); + + public static final String COMMAND_WORD = "save"; + + public static final String MESSAGE_DIRECTORY_EXAMPLE = "C://Users/User PC/Downloads/"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Changes data file location of Malitio.\n" + + "Parameters: File Directory\n" + + "Example: " + COMMAND_WORD + + " " + MESSAGE_DIRECTORY_EXAMPLE; + + public static final String MESSAGE_SAVE_SUCCESSFUL = "Malitio data will be saved in %s from now onwards."; + + public static final String MESSAGE_INVALID_DIRECTORY = "The directory is invalid! Valid file paths must end with '/' or '\\'\nExample: "; + + public static final String[] FILE_PATH_IDENTIFIER = {"\\", "/" }; + + private final String dataFilePath; + + /** + * Initialises dataFilePath to the input if the input ends with '/' or '\', else set dataFilePath to null + * + */ + public SaveCommand(String dataFilePath) { + if(dataFilePath.endsWith(FILE_PATH_IDENTIFIER[0]) || dataFilePath.endsWith(FILE_PATH_IDENTIFIER[1])) { + this.dataFilePath = dataFilePath + Config.DEFAULT_FILE_NAME; + } else { + this.dataFilePath = null; + } + } + + @Override + public CommandResult execute() { + if(!isValidFilePath()) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(MESSAGE_INVALID_DIRECTORY + MESSAGE_DIRECTORY_EXAMPLE); + } + EventsCenter.getInstance().post(new DataStorageFileChangedEvent(dataFilePath)); + ConfigUtil.changeMalitioSaveDirectory(dataFilePath); + model.dataFilePathChanged(); + + return new CommandResult(String.format(MESSAGE_SAVE_SUCCESSFUL, dataFilePath)); + } + + /** + * Checks if the input by user is a valid file path. Valid file paths must end with '/' and cannot contain '\' + */ + private boolean isValidFilePath() { + if(dataFilePath == null) { + return false; + } + + File file = new File(dataFilePath); + try { + if(!FileUtil.createFile(file)) { + logger.warning("File already exists"); + } + return true; + } catch (IOException e) { + return false; + } + } +} diff --git a/src/main/java/seedu/malitio/logic/commands/UncompleteCommand.java b/src/main/java/seedu/malitio/logic/commands/UncompleteCommand.java new file mode 100644 index 000000000000..d505cf569e78 --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/UncompleteCommand.java @@ -0,0 +1,106 @@ +package seedu.malitio.logic.commands; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.commons.exceptions.IllegalValueException; + +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineNotFoundException; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineUncompletedException; +import seedu.malitio.model.task.UniqueFloatingTaskList; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskUncompletedException; + +//@@author A0122460W +/** + * Uncomplete a floating task/ deadline identified using it's last displayed + * index from Malitio. unstrikeout the completed floating task/ deadline + * + */ +public class UncompleteCommand extends Command { + + public static final String COMMAND_WORD = "uncomplete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": uncomplete the task or deadline identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be either 'f'/'d' and a positive integer) " + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_UNCOMPLETED_TASK = "The floating task is already uncompleted in Malitio"; + + public static final String MESSAGE_UNCOMPLETED_DEADLINE = "The deadline is already uncompleted in Malitio"; + + public static final String MESSAGE_UNCOMPLETED_TASK_SUCCESS = "Successfully uncomplete floating task."; + + public static final String MESSAGE_UNCOMPLETED_DEADLINE_SUCCESS = "Successfully uncomplete deadline."; + + private final char taskType; + + private final int targetIndex; + + public UncompleteCommand(char taskType, int targetIndex) throws IllegalValueException { + assert taskType == 'd' || taskType == 'f'; + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + CommandResult result; + if (taskType == 'f') { + result = executeUncompleteFloatingTask(); + model.getFuture().clear(); + return result; + } else { + result = executeUncompleteDeadline(); + model.getFuture().clear(); + return result; + } + } + + private CommandResult executeUncompleteFloatingTask() { + UnmodifiableObservableList lastShownList = model.getFilteredFloatingTaskList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyFloatingTask taskToUncomplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.uncompleteTask(taskToUncomplete); + } catch (FloatingTaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } catch (UniqueFloatingTaskList.FloatingTaskUncompletedException e) { + return new CommandResult(MESSAGE_UNCOMPLETED_TASK); + } catch (DeadlineUncompletedException e) { + } catch (DeadlineNotFoundException e) { + } + return new CommandResult(String.format(MESSAGE_UNCOMPLETED_TASK_SUCCESS, taskToUncomplete)); + } + + private CommandResult executeUncompleteDeadline() { + UnmodifiableObservableList lastShownList = model.getFilteredDeadlineList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + } + + ReadOnlyDeadline deadlineToUncomplete = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.uncompleteTask(deadlineToUncomplete); + } catch (DeadlineNotFoundException pnfe) { + assert false : "The target deadline cannot be missing"; + } catch (UniqueDeadlineList.DeadlineUncompletedException e) { + return new CommandResult(MESSAGE_UNCOMPLETED_DEADLINE); + } catch (FloatingTaskUncompletedException e) { + } catch (FloatingTaskNotFoundException e) { + } + return new CommandResult(String.format(MESSAGE_UNCOMPLETED_DEADLINE_SUCCESS, deadlineToUncomplete)); + } + +} diff --git a/src/main/java/seedu/malitio/logic/commands/UndoCommand.java b/src/main/java/seedu/malitio/logic/commands/UndoCommand.java new file mode 100644 index 000000000000..8b821bbbb2be --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/UndoCommand.java @@ -0,0 +1,182 @@ +package seedu.malitio.logic.commands; + +import java.util.Stack; + +import seedu.malitio.model.Malitio; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.history.InputAddHistory; +import seedu.malitio.model.history.InputClearHistory; +import seedu.malitio.model.history.InputCompleteHistory; +import seedu.malitio.model.history.InputDeleteHistory; +import seedu.malitio.model.history.InputEditHistory; +import seedu.malitio.model.history.InputHistory; +import seedu.malitio.model.history.InputMarkHistory; +import seedu.malitio.model.history.InputUncompleteHistory; +import seedu.malitio.model.history.InputUnmarkHistory; + +//@@author A0129595N +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_UNDO_ADD_SUCCESS = "Undo successful. Undo add %1$s"; + public static final String MESSAGE_UNDO_DELETE_SUCCESS = "Undo Successful. Undo delete %1$s"; + public static final String MESSAGE_UNDO_CLEAR_SUCCESS = "Undo clear successful"; + public static final String MESSAGE_UNDO_EDIT_SUCCESS = "Undo successful. Undo edit from %1$s to %2$s"; + public static final String MESSAGE_UNDO_MARK_SUCCESS = "Undo mark sucessful"; + public static final String MESSAGE_UNDO_UNMARK_SUCCESS = "Undo unmark sucessful"; + public static final String MESSAGE_UNDO_COMPLETE_SUCCESS = "Undo complete successful"; + public static final String MESSAGE_UNDO_UNCOMPLETE_SUCCESS = "Undo uncomplete successful"; + public String result; + + @Override + public CommandResult execute() { + + Stack history = model.getHistory(); + if (history.isEmpty()) { + return new CommandResult("No action to undo!"); + } + InputHistory previous = history.pop(); + switch (previous.getUndoCommand()) { + + case AddCommand.COMMAND_WORD: + result = executeAdd((InputDeleteHistory) previous); + updateModel(history); + return new CommandResult(result); + + case DeleteCommand.COMMAND_WORD: + result = executeDelete((InputAddHistory) previous); + updateModel(history); + return new CommandResult(result); + + case EditCommand.COMMAND_WORD: + result = executeEdit((InputEditHistory) previous); + updateModel(history); + return new CommandResult(result); + + case ClearCommand.COMMAND_WORD: + result = executeClear((InputClearHistory) previous); + updateModel(history); + return new CommandResult(result); + + case UnmarkCommand.COMMAND_WORD: + result = executeUnmark((InputMarkHistory) previous); + updateModel(history); + return new CommandResult(result); + + case MarkCommand.COMMAND_WORD: + result = executeMark((InputUnmarkHistory) previous); + updateModel(history); + return new CommandResult(result); + + case UncompleteCommand.COMMAND_WORD: + result = executeUncomplete((InputCompleteHistory) previous); + updateModel(history); + return new CommandResult(result); + + case CompleteCommand.COMMAND_WORD: + result = executeComplete((InputUncompleteHistory) previous); + updateModel(history); + return new CommandResult(result); + + default: + assert false; + return null; + } + } + + //========== Private helper methods ================================================== + + public String executeAdd(InputDeleteHistory previous) { + try { + if (previous.getPositionOfFloatingTask() != -1) { + model.addFloatingTaskAtSpecificPlace(previous.getTask(), previous.getPositionOfFloatingTask()); + } else { + model.addTask(previous.getTask()); + } + } catch (Exception e) { + assert false : "Not possible"; + } + return String.format(MESSAGE_UNDO_DELETE_SUCCESS, previous.getTask().toString()); + } + + public String executeDelete(InputAddHistory previous) { + try { + model.deleteTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not Possible"; + } + return String.format(MESSAGE_UNDO_ADD_SUCCESS, previous.getTask().toString()); + } + + private String executeEdit(InputEditHistory previous) { + try { + model.editTask(previous.getEditedTask(), previous.getTaskToEdit()); + } catch (Exception e) { + assert false : "Not possible"; + } + return String.format(MESSAGE_UNDO_EDIT_SUCCESS, previous.getTaskToEdit().toString(), + previous.getEditedTask().toString()); + } + + private String executeClear(InputClearHistory previous) { + ReadOnlyMalitio previousModel = new Malitio(previous.getFloatingTask(), previous.getDeadline(), previous.getEvent(), previous.getTag()); + model.resetData(previousModel); + return MESSAGE_UNDO_CLEAR_SUCCESS; + } + + private String executeUnmark(InputMarkHistory previous) { + try { + model.unmarkTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_UNDO_MARK_SUCCESS; + } + + private String executeMark(InputUnmarkHistory previous) { + try { + model.markTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_UNDO_UNMARK_SUCCESS; + } + + private String executeUncomplete(InputCompleteHistory previous) { + try { + model.uncompleteTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_UNDO_COMPLETE_SUCCESS; + } + + private String executeComplete(InputUncompleteHistory previous) { + try { + model.completeTask(previous.getTask()); + } catch (Exception e) { + assert false : "Not possible"; + } + return MESSAGE_UNDO_UNCOMPLETE_SUCCESS; + } + + private void updateModel(Stack history) { + showAllListsInModel(); + updateRedoStack(history); + } + + private void showAllListsInModel() { + model.updateFilteredTaskListToShowAll(); + model.updateFilteredDeadlineListToShowAll(); + model.updateFilteredEventListToShowAll(); + } + + /** + * Updates the redo stack with InputHistory of the action undone. + * @param history + */ + private void updateRedoStack(Stack history) { + model.getFuture().push(history.pop()); + } + +} diff --git a/src/main/java/seedu/malitio/logic/commands/UnmarkCommand.java b/src/main/java/seedu/malitio/logic/commands/UnmarkCommand.java new file mode 100644 index 000000000000..3fe81c009c4b --- /dev/null +++ b/src/main/java/seedu/malitio/logic/commands/UnmarkCommand.java @@ -0,0 +1,85 @@ +package seedu.malitio.logic.commands; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineNotFoundException; +import seedu.malitio.model.task.UniqueDeadlineList.DeadlineUnmarkedException; +import seedu.malitio.model.task.UniqueEventList.EventNotFoundException; +import seedu.malitio.model.task.UniqueEventList.EventUnmarkedException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskUnmarkedException; + +/** + * Unmarks a specified task or deadline as a priority in Malitio to the user. + * @@author A0153006W + */ +public class UnmarkCommand extends Command { + + public static final String COMMAND_WORD = "unmark"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Unmarks specified task or deadline as priority in Malitio\n" + + "Parameters: INDEX\n" + "Example: " + COMMAND_WORD + " f1"; + + public static final String MESSAGE_UNMARK_SUCCESS = "Task has been unmarked as priority"; + public static final String MESSAGE_UNMARK_AGAIN = "Task has already been unmarked as priority"; + + private final int targetIndex; + private final char taskType; + + private Object taskToUnmark; + + public UnmarkCommand(char taskType, int targetIndex) { + this.taskType = taskType; + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + if (!(taskType == 'f' || taskType == 'd' || taskType == 'e')) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + UnmodifiableObservableList lastShownList; + lastShownList = getCorrectList(); + if (lastShownList.size() < targetIndex || targetIndex <= 0) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + taskToUnmark = lastShownList.get(targetIndex - 1); + + try { + assert model != null; + model.unmarkTask(taskToUnmark); + } catch (FloatingTaskNotFoundException e) { + assert false : "The target floating task cannot be missing"; + } catch (FloatingTaskUnmarkedException e) { + return new CommandResult(MESSAGE_UNMARK_AGAIN); + } catch (DeadlineNotFoundException e) { + assert false : "The target deadline cannot be missing"; + } catch (DeadlineUnmarkedException e) { + return new CommandResult(MESSAGE_UNMARK_AGAIN); + } catch (EventNotFoundException e) { + assert false : "The target event cannot be missing"; + } catch (EventUnmarkedException e) { + return new CommandResult(MESSAGE_UNMARK_AGAIN); + } + return new CommandResult(MESSAGE_UNMARK_SUCCESS); + } + + /** + * @return UnmodifiableObservableList of the correct task type + */ + private UnmodifiableObservableList getCorrectList() { + UnmodifiableObservableList lastShownList; + if (taskType == 'f') { + lastShownList = model.getFilteredFloatingTaskList(); + } else if (taskType == 'd') { + lastShownList = model.getFilteredDeadlineList(); + } else { + lastShownList = model.getFilteredEventList(); + } + return lastShownList; + } +} \ No newline at end of file diff --git a/src/main/java/seedu/malitio/logic/parser/DateParser.java b/src/main/java/seedu/malitio/logic/parser/DateParser.java new file mode 100644 index 000000000000..12f0d8d0a46b --- /dev/null +++ b/src/main/java/seedu/malitio/logic/parser/DateParser.java @@ -0,0 +1,30 @@ +package seedu.malitio.logic.parser; + +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import com.joestelmach.natty.DateGroup; +import com.joestelmach.natty.Parser; + +/** + * A Parser class that implements natty library to convert string objects into dates. + * Returns a null date object if the argument is not recognised as a date. + */ +//@author a0126633j +public class DateParser { + + private static Parser dateParser = new Parser(TimeZone.getDefault()); + + public DateParser() {} + + public static Date parse(String date) { + List parsedDates = dateParser.parse(date); + + if(parsedDates != null && !parsedDates.isEmpty()) { + return parsedDates.get(0).getDates().get(0); + } else { + return null; + } + } +} diff --git a/src/main/java/seedu/malitio/logic/parser/Parser.java b/src/main/java/seedu/malitio/logic/parser/Parser.java new file mode 100644 index 000000000000..8ad29532d67b --- /dev/null +++ b/src/main/java/seedu/malitio/logic/parser/Parser.java @@ -0,0 +1,487 @@ +package seedu.malitio.logic.parser; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.commons.util.StringUtil; +import seedu.malitio.logic.commands.*; + +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.malitio.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Parses user input. + */ +public class Parser { + + /** + * Used for initial separation of command word and args. + */ + private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); + + private static final Pattern TASK_INDEX_ARGS_FORMAT = Pattern.compile("(?)[e|d|f|E|D|F]\\d+"); + + private static final Pattern KEYWORDS_ARGS_FORMAT = + Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace + + private static final Pattern TASK_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes + Pattern.compile("(?[^/]+)" + + "(?(?: t/[^/]+)*)"); // variable number of tags + + private static final Pattern EDIT_DATA_ARGS_FORMAT = + + Pattern.compile("(?[e|d|f|E|D|F]\\d+)" + + "(?(?:\\s[^/]+)?)" + + "(?(?: t/[^/]+)*)"); + + private static final Pattern COMPLETE_INDEX_ARGS_FORMAT = Pattern.compile("(?[d|f|D|F]\\d+)"); + + private static final Set TYPES_OF_TASKS = new HashSet(Arrays.asList("f", "d", "e" )); + + public static final String MESSAGE_MISSING_START_END = "Expecting start and end times\nExample: start thursday 0800 end thursday 0900"; + + public Parser() {} + + /** + * Parses user input into command for execution. + * + * @param userInput full user input string + * @return the command based on the user input + */ + public Command parseCommand(String userInput) { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + final String arguments = matcher.group("arguments"); + switch (commandWord) { + + case AddCommand.COMMAND_WORD: + return prepareAdd(arguments); + + case EditCommand.COMMAND_WORD: + return prepareEdit(arguments); + + case DeleteCommand.COMMAND_WORD: + return prepareDelete(arguments); + + case CompleteCommand.COMMAND_WORD: + return prepareComplete(arguments); + + case UncompleteCommand.COMMAND_WORD: + return prepareUncomplete(arguments); + + case MarkCommand.COMMAND_WORD: + return prepareMark(arguments); + + case UnmarkCommand.COMMAND_WORD: + return prepareUnmark(arguments); + + case ClearCommand.COMMAND_WORD: + return prepareClear(arguments); + + case ListAllCommand.COMMAND_WORD: + return new ListAllCommand(); + + case FindCommand.COMMAND_WORD: + return prepareFind(arguments); + + case ListCommand.COMMAND_WORD: + return prepareList(arguments); + + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); + + case HelpCommand.COMMAND_WORD: + return new HelpCommand(); + + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + + case RedoCommand.COMMAND_WORD: + return new RedoCommand(); + + case SaveCommand.COMMAND_WORD: + return prepareSave(arguments); + + default: + return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); + } + } + + //@@author a0126633j + /** + * Parses arguments in the context of the clear command. Also checks validity of arguments + */ + private Command prepareClear(String arguments) { + if (!Arrays.asList(ClearCommand.VALID_ARGUMENTS).contains(arguments.trim().toLowerCase())) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ClearCommand.MESSAGE_USAGE)); + } + return new ClearCommand(arguments.trim().toLowerCase()); + } + + /** + * Parses arguments in the context of the save command. Also ensure the argument is not empty + */ + private Command prepareSave(String arguments) { + if (arguments.trim().isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SaveCommand.MESSAGE_USAGE)); + } + return new SaveCommand(arguments.trim()); + } + //@@author + + /** + * Parses arguments in the context of the add task command. + * + * @param args full command args string + * @return the prepared command + * @@author A0153006W + */ + private Command prepareAdd(String args){ + final Matcher matcher = TASK_DATA_ARGS_FORMAT.matcher(args.trim()); + boolean hasStart = false; + boolean hasEnd = false; + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + try { + String name = matcher.group("name"); + String deadline = getDeadlineFromArgs(StringUtil.removeTagsFromString(name)); + + String start = getStartFromArgs(StringUtil.removeTagsFromString(name)); + if (!start.isEmpty()) { + name = name.substring(0, name.lastIndexOf("start")).trim(); + hasStart = true; + } + + String end = getEndFromArgs(StringUtil.removeTagsFromString(args)); + if (!end.isEmpty()) { + hasEnd = true; + } + if (!deadline.isEmpty()) { + name = name.substring(0, name.lastIndexOf("by")).trim(); + } + if (!deadline.isEmpty() && !hasStart && !hasEnd) { + return new AddCommand( + name, + deadline, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (hasStart && hasEnd) { + return new AddCommand( + name, + start, + end, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } else if (hasStart ^ hasEnd) { + return new IncorrectCommand(MESSAGE_MISSING_START_END); + } + return new AddCommand( + name, + getTagsFromArgs(matcher.group("tagArguments")) + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + //@@author A0129595N + /** + * Parses arguments in the context of the edit task command. + * + * @param arguments + * @return the prepared command + */ + private Command prepareEdit(String args) { + final Matcher matcher = EDIT_DATA_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + String name = matcher.group("name"); + if (name.equals("") && getTagsFromArgs(matcher.group("tagArguments")).isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + String deadline = getDeadlineFromArgs(name); + if (!deadline.isEmpty()) { + name = name.replaceAll(" by " + deadline, ""); + } + + String start = getStartFromArgs(name); + if (!start.isEmpty()) { + name = name.replaceAll(" start " + start, ""); + } + + String end = getEndFromArgs(name); + if (!end.isEmpty()) { + name = name.replaceAll(" end " + end, ""); + } + name = name.trim(); + return new EditCommand( + taskType, + taskNum, + name, + deadline, + start, + end, + getTagsFromArgs(matcher.group("tagArguments")) + ); + + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + //@@author A0122460W + /** + * Parses arguments in the context of the complete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareComplete(String args) { + final Matcher matcher = COMPLETE_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new CompleteCommand(taskType,taskNum); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + /** + * Parses arguments in the context of the uncomplete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareUncomplete(String args) { + final Matcher matcher = COMPLETE_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UncompleteCommand.MESSAGE_USAGE)); + } + try { + String index = parseIndex(matcher.group("targetIndex")); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UncompleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new UncompleteCommand(taskType,taskNum); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + //@@author + /** + * Parses arguments in the context of the delete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareDelete(String args) { + String index = parseIndex(args); + if(index.isEmpty()) { + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + + return new DeleteCommand(Character.toString(taskType), taskNum); + } + + /** + * Parses arguments in the context of the mark task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareMark(String args) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkCommand.MESSAGE_USAGE)); + } + String index = parseIndex(args); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MarkCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + return new MarkCommand(taskType, taskNum); + } + + /** + * Parses arguments in the context of the unmark task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareUnmark(String args) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnmarkCommand.MESSAGE_USAGE)); + } + String index = parseIndex(args); + if (index.isEmpty()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnmarkCommand.MESSAGE_USAGE)); + } + char taskType = index.charAt(0); + int taskNum = Integer.parseInt(index.substring(1)); + return new UnmarkCommand(taskType, taskNum); + } + + /** + * Parses arguments in the context of the find task command. + * + * @param args full command args string + * @return the prepared command + * @@author + */ + private Command prepareFind(String args) { + final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + // keywords delimited by whitespace + String[] keywords = matcher.group("keywords").split("\\s+"); + String typeOfTask = ""; + + if(TYPES_OF_TASKS.contains(keywords[0])) { + typeOfTask = keywords[0]; + keywords = removeFirstFromArray(keywords); + } + if (keywords.length < 1) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + final Set keywordSet = new HashSet<>(Arrays.asList(keywords)); + return new FindCommand(typeOfTask, keywordSet); + } + + //@@author a0126633j + private String[] removeFirstFromArray(String[] arg) { + String[] result = new String[arg.length - 1]; + for(int i = 1; i < arg.length; i++) { + result[i - 1] = arg[i]; + } + return result; + } + + /** + * Parses arguments in the context of the list task command. + * + * @param args full command args string + * @return the prepared command + * @@author A0153006W + */ + private Command prepareList(String args) { + if (args.isEmpty()) { + return new ListCommand(); + } + try { + args = args.trim().toLowerCase(); + return new ListCommand(args); + } catch (IllegalValueException ive) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE)); + } + } + + /** + * Returns the specified index as a String in the {@code command} + */ + private String parseIndex(String command) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim()); + if (!matcher.matches()) { + return ""; + } + String index = command.trim().toLowerCase(); + return index; + } + + /** + * Extracts the task's deadline from the command's arguments string. + */ + private static String getDeadlineFromArgs(String args) throws IllegalValueException { + int byIndex = args.lastIndexOf(" by "); + String deadline = ""; + if(byIndex >= 0 && byIndex < args.length() - 4) { + deadline = args.substring(byIndex + 4); + } + return deadline; + } + + /** + * Extracts the task's event start from the command's arguments string. + */ + private static String getStartFromArgs(String args) throws IllegalValueException { + int startIndex = args.lastIndexOf(" start "); + int endIndex = args.lastIndexOf(" end"); + if (startIndex >= 0 && endIndex > 0) { + return args.substring(startIndex + 7, endIndex); + } else if (startIndex >= 0 && endIndex < 0) { + return args.substring(startIndex + 7); + } else { + return ""; + } + } + + /** + * Extracts the task's event end from the command's arguments string. + */ + private static String getEndFromArgs(String args) throws IllegalValueException { + int endIndex = args.lastIndexOf(" end "); + if (endIndex >= 0) { + return args.substring(endIndex + 5); + } else { + return ""; + } + } + + /** + * Extracts the new task's tags from the add command's tag arguments string. + * Merges duplicate tag strings. + * @@author + */ + private static Set getTagsFromArgs(String tagArguments) throws IllegalValueException { + // no tags + if (tagArguments.isEmpty()) { + return Collections.emptySet(); + } + // replace first delimiter prefix, then split + final Collection tagStrings = Arrays.asList(tagArguments.replaceFirst(" t/", "").split(" t/")); + return new HashSet<>(tagStrings); + } +} \ No newline at end of file diff --git a/src/main/java/seedu/malitio/model/Malitio.java b/src/main/java/seedu/malitio/model/Malitio.java new file mode 100644 index 000000000000..e9fcf4b8f00f --- /dev/null +++ b/src/main/java/seedu/malitio/model/Malitio.java @@ -0,0 +1,416 @@ +package seedu.malitio.model; + +import javafx.collections.ObservableList; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; +import seedu.malitio.model.task.UniqueDeadlineList.*; +import seedu.malitio.model.task.UniqueEventList.*; +import seedu.malitio.model.task.UniqueFloatingTaskList.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Wraps all data at the application level Duplicates are not allowed (by + * .equals comparison) + */ +public class Malitio implements ReadOnlyMalitio { + + private final UniqueFloatingTaskList tasks; + private final UniqueDeadlineList deadlines; + private final UniqueEventList events; + private final UniqueTagList tags; + + { + tasks = new UniqueFloatingTaskList(); + deadlines = new UniqueDeadlineList(); + events = new UniqueEventList(); + tags = new UniqueTagList(); + } + + public Malitio() { + } + + /** + * Tasks, Schedules and Tags are copied into this Malitio + */ + public Malitio(ReadOnlyMalitio toBeCopied) { + this(toBeCopied.getUniqueFloatingTaskList(), toBeCopied.getUniqueDeadlineList(), + toBeCopied.getUniqueEventList(), toBeCopied.getUniqueTagList()); + } + + /** + * Tasks and Tags are copied into this Malitio + */ + public Malitio(UniqueFloatingTaskList tasks, UniqueDeadlineList deadlines, UniqueEventList event, + UniqueTagList tags) { + resetData(tasks.getInternalList(), deadlines.getInternalList(), event.getInternalList(), + tags.getInternalList()); + } + + public static ReadOnlyMalitio getEmptymalitio() { + return new Malitio(); + } + + //// list overwrite operations + + public ObservableList getFloatingTasks() { + return tasks.getInternalList(); + } + + public ObservableList getDeadlines() { + deadlines.sort(); + return deadlines.getInternalList(); + } + + public ObservableList getEvents() { + events.sort(); + return events.getInternalList(); + } + + public void setTasks(List floatingTask) { + this.tasks.getInternalList().setAll(floatingTask); + } + + public void setDeadlines(List deadlines) { + this.deadlines.getInternalList().setAll(deadlines); + } + + public void setEvents(List events) { + this.events.getInternalList().setAll(events); + } + + public void setTags(Collection tags) { + this.tags.getInternalList().setAll(tags); + } + + public void resetData(Collection newTasks, + Collection newDeadlines, Collection newEvents, + Collection newTags) { + setTasks(newTasks.stream().map(FloatingTask::new).collect(Collectors.toList())); + setDeadlines(newDeadlines.stream().map(Deadline::new).collect(Collectors.toList())); + setEvents(newEvents.stream().map(t -> { + try { + return new Event(t); + } catch (IllegalValueException e) { + e.printStackTrace(); + } + return null; + }).collect(Collectors.toList())); + setTags(newTags); + } + + public void resetData(ReadOnlyMalitio newData) { + resetData(newData.getFloatingTaskList(), newData.getDeadlineList(), newData.getEventList(), + newData.getTagList()); + } + + //// task-level operations + //@@author A0129595N + /** + * Adds a task to Malitio. Also checks the new task's tags and updates + * {@link #tags} with any new tags found, and updates the Tag objects in the + * task to point to those in {@link #tags}. + * + * @throws UniqueFloatingTaskList.DuplicateFloatingTaskException + * if an equivalent task already exists. + * @throws DuplicateDeadlineException + * @throws DuplicateEventException + */ + public void addTask(Object p) + throws DuplicateFloatingTaskException, DuplicateDeadlineException, DuplicateEventException { + addToCorrectList(p); + syncTagsWithMasterList(p); + } + + /** + * Checks for the type of the p and adds to the correct list in Malitio. + * + * @param p + * task which can be FloatingTask, Deadline or Event + * @throws DuplicateFloatingTaskException + * @throws DuplicateDeadlineException + * @throws DuplicateEventException + */ + private void addToCorrectList(Object p) + throws DuplicateFloatingTaskException, DuplicateDeadlineException, DuplicateEventException { + if (isFloatingTask(p)) { + tasks.add((FloatingTask) p); + } else if (isDeadline(p)) { + deadlines.add((Deadline) p); + deadlines.sort(); + } else { + events.add((Event) p); + events.sort(); + } + } + + public void addTask(Object p, int index) throws UniqueFloatingTaskList.DuplicateFloatingTaskException { + syncTagsWithMasterList(p); + tasks.add((FloatingTask) p, index); + } + + /** + * Ensures that every tag in this task: - exists in the master list + * {@link #tags} - points to a Tag object in the master list + */ + private void syncTagsWithMasterList(Object task) { + final UniqueTagList taskTags = getTagsListFromTask(task); + tags.mergeFrom(taskTags); + + // Create map with values = tag object references in the master list + final Map masterTagObjects = new HashMap<>(); + for (Tag tag : tags) { + masterTagObjects.put(tag, tag); + } + + // Rebuild the list of task tags using references from the master list + final Set commonTagReferences = new HashSet<>(); + for (Tag tag : taskTags) { + commonTagReferences.add(masterTagObjects.get(tag)); + } + setTagsToTask(task, commonTagReferences); + } + + private boolean isFloatingTask(Object p) { + return p instanceof FloatingTask || p instanceof ReadOnlyFloatingTask; + } + + private boolean isDeadline(Object p) { + return p instanceof Deadline || p instanceof ReadOnlyDeadline; + } + + /** + * Check for the correct task type and set tags to it. + * + * @param task + * task can be either FloatingTask, Deadline or Event + * @param commonTagReferences + * set of tags to be added to the task + */ + private void setTagsToTask(Object task, final Set commonTagReferences) { + if (isFloatingTask(task)) { + ((FloatingTask) task).setTags(new UniqueTagList(commonTagReferences)); + } else if (isDeadline(task)) { + ((Deadline) task).setTags(new UniqueTagList(commonTagReferences)); + } else { + ((Event) task).setTags(new UniqueTagList(commonTagReferences)); + } + } + + /** + * Check for the correct task type and get tag list from it. + * + * @param task + * task can be either FloatingTask, Deadline or Event + * @return UniqueTagList of the task + */ + private UniqueTagList getTagsListFromTask(Object task) { + UniqueTagList taskTags; + if (isFloatingTask(task)) { + taskTags = ((FloatingTask) task).getTags(); + } else if (isDeadline(task)) { + taskTags = ((Deadline) task).getTags(); + } else { + taskTags = ((Event) task).getTags(); + } + return taskTags; + } + + public boolean removeTask(Object key) + throws FloatingTaskNotFoundException, DeadlineNotFoundException, EventNotFoundException { + if (isFloatingTask(key)) { + return removeFloatingTask(key); + } else if (isDeadline(key)) { + return removeDeadline(key); + } else { + return removeEvent(key); + } + } + + private boolean removeEvent(Object key) throws EventNotFoundException { + if (events.remove((ReadOnlyEvent) key)) { + return true; + } else { + throw new EventNotFoundException(); + } + } + + private boolean removeDeadline(Object key) throws DeadlineNotFoundException { + if (deadlines.remove((ReadOnlyDeadline) key)) { + return true; + } else { + throw new DeadlineNotFoundException(); + } + } + + private boolean removeFloatingTask(Object key) throws FloatingTaskNotFoundException { + if (tasks.remove((ReadOnlyFloatingTask) key)) { + return true; + } else { + throw new FloatingTaskNotFoundException(); + } + } + + public void editTask(Object edited, Object beforeEdit) + throws FloatingTaskNotFoundException, DuplicateFloatingTaskException, DuplicateDeadlineException, + DeadlineNotFoundException, DuplicateEventException, EventNotFoundException { + syncTagsWithMasterList(edited); + editTaskAccordingToTaskType(edited, beforeEdit); + } + + /** + * Checks for the task type of the edited and beforeEdit objects and assign + * the editing accordingly. + * + * @param edited + * the edited task + * @param beforeEdit + * the task to be edited + * @throws DuplicateFloatingTaskException + * @throws FloatingTaskNotFoundException + * @throws DuplicateDeadlineException + * @throws DeadlineNotFoundException + * @throws DuplicateEventException + * @throws EventNotFoundException + */ + private void editTaskAccordingToTaskType(Object edited, Object beforeEdit) + throws DuplicateFloatingTaskException, FloatingTaskNotFoundException, DuplicateDeadlineException, + DeadlineNotFoundException, DuplicateEventException, EventNotFoundException { + if (edited instanceof FloatingTask && beforeEdit instanceof ReadOnlyFloatingTask) { + tasks.edit((FloatingTask) edited, (ReadOnlyFloatingTask) beforeEdit); + } else if (edited instanceof Deadline && beforeEdit instanceof ReadOnlyDeadline) { + deadlines.edit((Deadline) edited, (ReadOnlyDeadline) beforeEdit); + deadlines.sort(); + } else { + events.edit((Event) edited, (Event) beforeEdit); + events.sort(); + } + } + + //@@author A0122460W + public void completeTask(Object taskToComplete) throws FloatingTaskCompletedException, + FloatingTaskNotFoundException, DeadlineCompletedException, DeadlineNotFoundException { + if (isFloatingTask(taskToComplete)) { + tasks.complete((ReadOnlyFloatingTask)taskToComplete); + } else { + deadlines.complete((ReadOnlyDeadline)taskToComplete); + } + } + + public void uncompleteTask(Object taskToUncomplete) throws FloatingTaskUncompletedException, + FloatingTaskNotFoundException, DeadlineUncompletedException, DeadlineNotFoundException { + if (isFloatingTask(taskToUncomplete)) { + tasks.uncomplete((ReadOnlyFloatingTask)taskToUncomplete); + } else { + deadlines.uncomplete((ReadOnlyDeadline)taskToUncomplete); + } + } + + //@@author A0153006W + public void markTask(Object taskToMark) throws FloatingTaskNotFoundException, FloatingTaskMarkedException, + DeadlineNotFoundException, DeadlineMarkedException, EventNotFoundException, EventMarkedException { + if (isFloatingTask(taskToMark)) { + tasks.mark((ReadOnlyFloatingTask) taskToMark); + } else if (isDeadline(taskToMark)) { + deadlines.mark((ReadOnlyDeadline) taskToMark); + } else { + events.mark((ReadOnlyEvent) taskToMark); + } + } + + public void unmarkTask(Object taskToUnmark) throws FloatingTaskNotFoundException, FloatingTaskUnmarkedException, + DeadlineNotFoundException, DeadlineUnmarkedException, EventNotFoundException, EventUnmarkedException { + if (isFloatingTask(taskToUnmark)) { + tasks.unmark((ReadOnlyFloatingTask) taskToUnmark); + } else if (isDeadline(taskToUnmark)) { + deadlines.unmark((ReadOnlyDeadline) taskToUnmark); + } else { + events.unmark((ReadOnlyEvent) taskToUnmark); + } + } + +//@@author +//// tag-level operations + + public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { + tags.add(t); + } + + //// util methods + + @Override + public String toString() { + return tasks.getInternalList().size() + " tasks, " + tags.getInternalList().size() + " tags"; + // TODO: refine later + } + + @Override + public List getFloatingTaskList() { + return Collections.unmodifiableList(tasks.getInternalList()); + } + + public List getDeadlineList() { + return Collections.unmodifiableList(deadlines.getInternalList()); + } + + @Override + public List getEventList() { + return Collections.unmodifiableList(events.getInternalList()); + } + + @Override + public List getTagList() { + return Collections.unmodifiableList(tags.getInternalList()); + } + + @Override + public UniqueFloatingTaskList getUniqueFloatingTaskList() { + return this.tasks; + } + + @Override + public UniqueDeadlineList getUniqueDeadlineList() { + return this.deadlines; + } + + @Override + public UniqueEventList getUniqueEventList() { + return this.events; + } + + @Override + public UniqueTagList getUniqueTagList() { + return this.tags; + } + + /** + * sort events by start date + */ + private void sortEvent() { + events.sort(); + } + + private void sortDeadline() { + deadlines.sort(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Malitio // instanceof handles nulls + && this.tasks.equals(((Malitio) other).tasks) + && this.deadlines.equals(((Malitio) other).deadlines) + && this.events.equals(((Malitio) other).events) && this.tags.equals(((Malitio) other).tags)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing + // your own + return Objects.hash(tasks, deadlines, events, tags); + } + +} diff --git a/src/main/java/seedu/malitio/model/Model.java b/src/main/java/seedu/malitio/model/Model.java new file mode 100644 index 000000000000..14bd28f5db9f --- /dev/null +++ b/src/main/java/seedu/malitio/model/Model.java @@ -0,0 +1,105 @@ +package seedu.malitio.model; + +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.model.history.InputHistory; +import seedu.malitio.model.task.*; +import seedu.malitio.model.task.UniqueEventList.*; +import seedu.malitio.model.task.UniqueFloatingTaskList.*; +import seedu.malitio.model.task.UniqueDeadlineList.*; + +import java.util.Set; +import java.util.Stack; + +/** + * The API of the Model component. + */ +public interface Model { + /** Clears existing backing model and replaces with the provided new data. */ + void resetData(ReadOnlyMalitio newData); + + /** Returns Malitio */ + ReadOnlyMalitio getMalitio(); + + /** Deletes the given task. */ + void deleteTask(Object target) throws FloatingTaskNotFoundException, DeadlineNotFoundException, EventNotFoundException; + + /** Adds the given task */ + void addTask(Object task) throws DuplicateFloatingTaskException, DuplicateDeadlineException, DuplicateEventException; + + /** Adds the given floating task at a specific index */ + void addFloatingTaskAtSpecificPlace(Object task, int index) throws DuplicateFloatingTaskException; + + /** Returns the filtered floating task list as an {@code UnmodifiableObservableList} */ + UnmodifiableObservableList getFilteredFloatingTaskList(); + + /** Returns the filtered deadline list as an {@code UnmodifiableObservableList} */ + UnmodifiableObservableList getFilteredDeadlineList(); + + /** Returns the filtered deadline list as an {@code UnmodifiableObservableList} */ + UnmodifiableObservableList getFilteredEventList(); + + /** Returns the History of the Model so far */ + Stack getHistory(); + + /** Returns the Future of the Model so far which are commands that are undo-ed */ + Stack getFuture(); + + /** Updates the filter of the filtered floating task list to show all tasks */ + void updateFilteredTaskListToShowAll(); + + /** Updates the filter of the filtered deadlines to show all deadlines */ + void updateFilteredDeadlineListToShowAll(); + + /** Updates the filter of the filtered events to show all events */ + void updateFilteredEventListToShowAll(); + + /** Updates the filter of the filtered task list to filter by the given keywords*/ + void updateFilteredTaskList(Set keywords); + + /** Updates the filter of the filtered deadlines to filter by the given keywords*/ + void updateFilteredDeadlineList(Set keywords); + + /** Updates the filter of the filtered deadlines to filter by the given time*/ + void updateFilteredDeadlineList(DateTime keyword); + + /** Updates the filter of the filtered events to filter by the given keywords*/ + void updateFilteredEventList(Set keywords); + + /** Updates the filter of the filtered deadlines to filter by the given time*/ + void updateFilteredEventList(DateTime keyword); + + /** Replaces the floating task with the intended edit.*/ + void editTask(Object editedTask, Object taskToEdit) + throws FloatingTaskNotFoundException, DuplicateFloatingTaskException, DuplicateDeadlineException, + DeadlineNotFoundException, DuplicateEventException, EventNotFoundException; + + /** Complete the task.*/ + void completeTask(Object taskToComplete) throws FloatingTaskCompletedException, + FloatingTaskNotFoundException, DeadlineCompletedException, DeadlineNotFoundException; + + /** Complete the task.*/ + void uncompleteTask(Object taskToUncomplete) throws FloatingTaskUncompletedException, + FloatingTaskNotFoundException, DeadlineUncompletedException, DeadlineNotFoundException; + + /** Marks the task as a priority */ + void markTask(Object taskToMark) throws FloatingTaskNotFoundException, FloatingTaskMarkedException, + DeadlineNotFoundException, DeadlineMarkedException, EventNotFoundException, EventMarkedException; + + /** Unmarks the task as a priority */ + void unmarkTask(Object taskToUnmark) throws FloatingTaskNotFoundException, FloatingTaskUnmarkedException, + DeadlineNotFoundException, DeadlineUnmarkedException, EventNotFoundException, EventUnmarkedException; + + /** Indicate the directory of data file has changed. Save data into new directory*/ + void dataFilePathChanged(); + + /** + * Deletes all completed deadlines and floating tasks and past events from the model. + */ + void clearExpiredTasks(); + + /** Show all task from beginning of time*/ + void ShowAllTask(); + + + +} diff --git a/src/main/java/seedu/malitio/model/ModelManager.java b/src/main/java/seedu/malitio/model/ModelManager.java new file mode 100644 index 000000000000..1d910509d254 --- /dev/null +++ b/src/main/java/seedu/malitio/model/ModelManager.java @@ -0,0 +1,535 @@ +package seedu.malitio.model; + +import javafx.collections.transformation.FilteredList; +import seedu.malitio.commons.events.ui.JumpToListRequestEvent; +import seedu.malitio.commons.core.ComponentManager; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.core.UnmodifiableObservableList; +import seedu.malitio.commons.events.model.MalitioChangedEvent; +import seedu.malitio.commons.util.StringUtil; + +import seedu.malitio.model.task.*; +import seedu.malitio.model.task.UniqueDeadlineList.*; +import seedu.malitio.model.task.UniqueEventList.*; +import seedu.malitio.model.task.UniqueFloatingTaskList.*; +import seedu.malitio.model.history.*; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Logger; + +import edu.emory.mathcs.backport.java.util.Arrays; + +/** + * Represents the in-memory model of the malitio data. + * All changes to any model should be synchronized. + */ +public class ModelManager extends ComponentManager implements Model { + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private final Malitio malitio; + private final FilteredList filteredFloatingTasks; + private final FilteredList filteredDeadlines; + private final FilteredList filteredEvents; + private Stack history; + private Stack future; + + /** + * Initializes a ModelManager with the given Malitio + * Malitio and its variables should not be null + */ + public ModelManager(Malitio src, UserPrefs userPrefs) { + super(); + assert src != null; + assert userPrefs != null; + + logger.fine("Initializing with malitio: " + src + " and user prefs " + userPrefs); + + malitio = new Malitio(src); + filteredFloatingTasks = new FilteredList<>(malitio.getFloatingTasks()); + filteredDeadlines = new FilteredList<>(malitio.getDeadlines()); + filteredEvents = new FilteredList<>(malitio.getEvents()); + history = new Stack(); + future = new Stack(); + } + + public ModelManager() { + this(new Malitio(), new UserPrefs()); + } + + public ModelManager(ReadOnlyMalitio initialData, UserPrefs userPrefs) { + malitio = new Malitio(initialData); + filteredFloatingTasks = new FilteredList<>(malitio.getFloatingTasks()); + filteredDeadlines = new FilteredList<>(malitio.getDeadlines()); + filteredEvents = new FilteredList<>(malitio.getEvents()); + history = new Stack(); + future = new Stack(); + } + + @Override + public void resetData(ReadOnlyMalitio newData) { + history.add(new InputClearHistory(malitio.getUniqueFloatingTaskList(), + malitio.getUniqueDeadlineList(), + malitio.getUniqueEventList(), + malitio.getUniqueTagList())); + malitio.resetData(newData); + indicateMalitioChanged(); + } + + + @Override + public ReadOnlyMalitio getMalitio() { + return malitio; + } + + /** Raises an event to indicate the model has changed */ + private void indicateMalitioChanged() { + raise(new MalitioChangedEvent(malitio)); + } + + @Override + public void deleteTask(Object target) throws FloatingTaskNotFoundException, DeadlineNotFoundException, EventNotFoundException { + addInputDeleteHistory(target); + malitio.removeTask(target); + indicateMalitioChanged(); + } + + private void addInputDeleteHistory(Object target) { + if (target instanceof ReadOnlyFloatingTask) { + history.add(new InputDeleteHistory(target, malitio.getUniqueFloatingTaskList().getInternalList())); + } else { + history.add(new InputDeleteHistory(target)); + } + } + + //@@author A0129595N + + @Override + public void addTask(Object task) + throws DuplicateFloatingTaskException, DuplicateDeadlineException, DuplicateEventException { + malitio.addTask(task); + history.add(new InputAddHistory(task)); + updateAllListToShowAll(); + indicateMalitioChanged(); + indicateTaskListChanged(task); + } + + @Override + public void addFloatingTaskAtSpecificPlace(Object task, int index) throws DuplicateFloatingTaskException { + malitio.addTask(task, index); + history.add(new InputAddHistory(task)); + updateFilteredTaskListToShowAll(); + indicateMalitioChanged(); + indicateTaskListChanged(task); + } + + @Override + public void editTask(Object edited, Object beforeEdit) throws FloatingTaskNotFoundException, DuplicateFloatingTaskException, DuplicateDeadlineException, + DeadlineNotFoundException, DuplicateEventException, EventNotFoundException { + malitio.editTask(edited, beforeEdit); + history.add(new InputEditHistory(edited, beforeEdit)); + updateAllListToShowAll(); + indicateMalitioChanged(); + indicateTaskListChanged(edited); + } + + //@@author A0122460W + @Override + public void completeTask(Object taskToComplete) throws FloatingTaskCompletedException, FloatingTaskNotFoundException, DeadlineCompletedException, DeadlineNotFoundException { + malitio.completeTask(taskToComplete); + history.add(new InputCompleteHistory(taskToComplete)); + updateAllListToShowAll(); + indicateMalitioChanged(); + indicateTaskListChanged(taskToComplete); + } + + @Override + public void uncompleteTask(Object taskToUncomplete) throws FloatingTaskUncompletedException, FloatingTaskNotFoundException, DeadlineUncompletedException, DeadlineNotFoundException { + malitio.uncompleteTask(taskToUncomplete); + history.add(new InputUncompleteHistory(taskToUncomplete)); + updateAllListToShowAll(); + indicateMalitioChanged(); + indicateTaskListChanged(taskToUncomplete); + } + + //@@author + @Override + public void markTask(Object taskToMark) throws FloatingTaskNotFoundException, FloatingTaskMarkedException, + DeadlineNotFoundException, DeadlineMarkedException, EventNotFoundException, EventMarkedException { + malitio.markTask(taskToMark); + history.add(new InputMarkHistory(taskToMark)); + updateAllListToShowAll(); + indicateTaskListChanged(taskToMark); + } + + @Override + public void unmarkTask(Object taskToUnmark) throws FloatingTaskNotFoundException, FloatingTaskUnmarkedException, + DeadlineNotFoundException, DeadlineUnmarkedException, EventNotFoundException, EventUnmarkedException { + malitio.unmarkTask(taskToUnmark); + history.add(new InputUnmarkHistory(taskToUnmark)); + updateAllListToShowAll(); + indicateTaskListChanged(taskToUnmark); + } + + private void updateAllListToShowAll() { + updateFilteredTaskListToShowAll(); + updateFilteredDeadlineListToShowAll(); + updateFilteredEventListToShowAll(); + + } + + @Override + public Stack getHistory() { + return history; + } + + @Override + public Stack getFuture() { + return future; + } + + //@@author a0126633j + @Override + public void dataFilePathChanged() { + logger.info("Data storage file path changed, updating.."); + indicateMalitioChanged(); + } + + @Override + public void clearExpiredTasks() { + + history.add(new InputClearHistory(malitio.getUniqueFloatingTaskList(), + malitio.getUniqueDeadlineList(), + malitio.getUniqueEventList(), + malitio.getUniqueTagList())); + + clearExpiredFloatingTasks(malitio.getFloatingTaskList()); + clearExpiredDeadlines(malitio.getDeadlineList()); + clearExpiredEvents(malitio.getEventList()); + + indicateMalitioChanged(); + } + + private void clearExpiredFloatingTasks(List list) { + List toBeRemoved = new ArrayList(); + + for (ReadOnlyFloatingTask task : list) { + if (task.getCompleted()) { + toBeRemoved.add(task); + } + } + for (ReadOnlyFloatingTask task : toBeRemoved) { + try { + malitio.removeTask(task); + } catch (FloatingTaskNotFoundException | DeadlineNotFoundException | EventNotFoundException e) { + assert(false); //impossible + } + } + } + private void clearExpiredDeadlines(List list) { + List toBeRemoved = new ArrayList(); + + for (ReadOnlyDeadline task : list) { + if (task.getCompleted()) { + toBeRemoved.add(task); + } + } + for (ReadOnlyDeadline task : toBeRemoved) { + try { + malitio.removeTask(task); + } catch (FloatingTaskNotFoundException | DeadlineNotFoundException | EventNotFoundException e) { + assert(false); //impossible + } + } + } + + private void clearExpiredEvents(List list) { + Date current = new Date(); + List toBeRemoved = new ArrayList(); + + for (ReadOnlyEvent task : list) { + if (current.after(task.getEnd().getDate())) { + toBeRemoved.add(task); + } + } + + for (ReadOnlyEvent task : toBeRemoved) { + try { + malitio.removeTask(task); + } catch (FloatingTaskNotFoundException | DeadlineNotFoundException | EventNotFoundException e) { + assert(false); //impossible + } + } + } + //@@author + + //@@author A0129595N + /** + * This method will post an event to indicate that a task has been added/modified. + * @param task the task which an action has been performed on it i.e. add/edit/mark/unmark/complete/uncomplete + */ + private void indicateTaskListChanged(Object task) { + String taskType; + int positionOfTask; + if (isFloatingTask(task)) { + taskType = "floating task"; + positionOfTask = filteredFloatingTasks.indexOf(task); + } else if (isDeadline(task)) { + taskType = "deadline"; + positionOfTask = filteredDeadlines.indexOf(task); + } else { + taskType = "event"; + positionOfTask =filteredEvents.indexOf(task); + } + raise(new JumpToListRequestEvent(positionOfTask, taskType)); + } + + private boolean isFloatingTask(Object task) { + return task instanceof FloatingTask; + } + + private boolean isDeadline(Object task) { + return task instanceof Deadline; + } + + //@@author + //=========== Filtered Task List Accessors =============================================================== + + + + @Override + public UnmodifiableObservableList getFilteredFloatingTaskList() { + return new UnmodifiableObservableList<>(filteredFloatingTasks); + } + + @Override + public UnmodifiableObservableList getFilteredDeadlineList() { + return new UnmodifiableObservableList<>(filteredDeadlines); + } + + @Override + public UnmodifiableObservableList getFilteredEventList() { + return new UnmodifiableObservableList<>(filteredEvents); + } + + @Override + public void ShowAllTask() { + filteredFloatingTasks.setPredicate(null); + filteredDeadlines.setPredicate(null); + filteredEvents.setPredicate(null); + } + + @Override + public void updateFilteredTaskListToShowAll() { + filteredFloatingTasks.setPredicate(null); + } + + @Override + public void updateFilteredDeadlineListToShowAll() { + filteredDeadlines.setPredicate(p->!p.getCompleted() || p.getDue().compareTo(new Date())>0); + } + + @Override + public void updateFilteredEventListToShowAll() { + filteredEvents.setPredicate(p ->p.getEnd().compareTo(new Date())>0); + } + + @Override + public void updateFilteredTaskList(Set keywords) { + updateFilteredTaskList(new PredicateExpression(new FindCommandQualifier(keywords, filteredFloatingTasks))); + } + + private void updateFilteredTaskList(Expression expression) { + filteredFloatingTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredDeadlineList(Set keywords) { + updateFilteredDeadlines(new PredicateExpression(new FindCommandQualifier(keywords, filteredDeadlines))); + } + + @Override + public void updateFilteredDeadlineList(DateTime keyword) { + updateFilteredDeadlines(new PredicateExpression(new TimeQualifier(keyword))); + } + + private void updateFilteredDeadlines(Expression expression) { + filteredDeadlines.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredEventList(Set keywords) { + updateFilteredEvents(new PredicateExpression(new FindCommandQualifier(keywords, filteredEvents))); + } + + @Override + public void updateFilteredEventList(DateTime keyword) { + updateFilteredEvents(new PredicateExpression(new TimeQualifier(keyword))); + } + + private void updateFilteredEvents(Expression expression) { + filteredEvents.setPredicate(expression::satisfies); + } + + //========== Inner classes/interfaces used for filtering ================================================== + + interface Expression { + boolean satisfies(Object task); + + String toString(); + } + + private class PredicateExpression implements Expression { + + private final Qualifier qualifier; + + PredicateExpression(Qualifier qualifier) { + this.qualifier = qualifier; + } + + @Override + public boolean satisfies(Object task) { + return qualifier.run(task); + } + + @Override + public String toString() { + return qualifier.toString(); + } + } + + interface Qualifier { + boolean run(Object task); + boolean run(ReadOnlyFloatingTask task); + boolean run(ReadOnlyDeadline task); + boolean run(ReadOnlyEvent task); + String toString(); + } + + //@@author a0126633j + /** + * A qualifier that checks if a task's name/tags/date/time is qualified. Only tasks in the current shown UI list is qualified. + * + */ + private class FindCommandQualifier implements Qualifier { + private Set nameKeyWords; + private List currentShownList; + + FindCommandQualifier(Set nameKeyWords, FilteredList listInput) { + this.nameKeyWords = nameKeyWords; + currentShownList = Arrays.asList(listInput.toArray()); + } + + @Override + public boolean run(Object task) { + if(isFloatingTask(task)) { + return nameKeyWords.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(((ReadOnlyFloatingTask) task).getName().fullName + + " " + StringUtil.reformatTagString(((ReadOnlyFloatingTask) task).tagsString()), keyword)) + .findAny() + .isPresent() + && + currentShownList.contains(task); + } else if (isDeadline(task)) { + + return nameKeyWords.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(((ReadOnlyDeadline) task).getName().fullName + + " " + StringUtil.reformatTagString(((ReadOnlyDeadline) task).tagsString()) + + " " + ((ReadOnlyDeadline) task).getDue().toString(), + keyword)) + .findAny() + .isPresent() + && + currentShownList.contains(task); + } else { + return nameKeyWords.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(((ReadOnlyEvent) task).getName().fullName + + " " + StringUtil.reformatTagString(((ReadOnlyEvent) task).tagsString()) + + " " + ((ReadOnlyEvent) task).getStart().toString() + + " " + ((ReadOnlyEvent) task).getEnd().toString(), + keyword)) + .findAny() + .isPresent() + && + currentShownList.contains(task); + } + + } + //@@author + + @Override + public boolean run(ReadOnlyFloatingTask task) { + return false; + } + + @Override + public boolean run(ReadOnlyDeadline task) { + return false; + } + + @Override + public boolean run(ReadOnlyEvent task) { + return false; + } + + + @Override + public String toString() { + return "name=" + String.join(", ", nameKeyWords); + } + + } + + private class TimeQualifier implements Qualifier { + private DateTime timeKeyWord; + + TimeQualifier(DateTime timeKeyWord) { + this.timeKeyWord = timeKeyWord; + } + + @Override + public boolean run(ReadOnlyFloatingTask task) { + return false; + } + + @Override + public boolean run(ReadOnlyDeadline deadline) { + if (timeKeyWord.compareTo(deadline.getDue()) <= 0) { + return true; + } else { + return false; + } + } + + @Override + public boolean run(ReadOnlyEvent event) { + if (timeKeyWord.compareTo(event.getStart()) <= 0) { + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return timeKeyWord.toString(); + } + + @Override + public boolean run(Object task) { + if (isFloatingTask(task)) { + return run((ReadOnlyFloatingTask) task); + } + else if (isDeadline(task)) { + return run((ReadOnlyDeadline) task); + } else { + return run((ReadOnlyEvent) task); + } + + } + } + +} diff --git a/src/main/java/seedu/malitio/model/ReadOnlyMalitio.java b/src/main/java/seedu/malitio/model/ReadOnlyMalitio.java new file mode 100644 index 000000000000..ba65f92c92e8 --- /dev/null +++ b/src/main/java/seedu/malitio/model/ReadOnlyMalitio.java @@ -0,0 +1,48 @@ +package seedu.malitio.model; + + +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueEventList; +import seedu.malitio.model.task.UniqueFloatingTaskList; + +import java.util.List; + +/** + * Unmodifiable view of an malitio + */ +public interface ReadOnlyMalitio { + + UniqueTagList getUniqueTagList(); + + UniqueFloatingTaskList getUniqueFloatingTaskList(); + + UniqueDeadlineList getUniqueDeadlineList(); + + UniqueEventList getUniqueEventList(); + + /** + * Returns an unmodifiable view of tasks list + */ + List getFloatingTaskList(); + + /** + * Returns an unmodifiable view of deadlines list + */ + List getDeadlineList(); + + /** + * Returns an unmodifiable view of deadlines list + */ + List getEventList(); + + /** + * Returns an unmodifiable view of tags list + */ + List getTagList(); + +} diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/malitio/model/UserPrefs.java similarity index 89% rename from src/main/java/seedu/address/model/UserPrefs.java rename to src/main/java/seedu/malitio/model/UserPrefs.java index da9c8037f495..58154eb46a99 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/seedu/malitio/model/UserPrefs.java @@ -1,9 +1,9 @@ -package seedu.address.model; - -import seedu.address.commons.core.GuiSettings; +package seedu.malitio.model; import java.util.Objects; +import seedu.malitio.commons.core.GuiSettings; + /** * Represents User's preferences. */ @@ -20,7 +20,7 @@ public void updateLastUsedGuiSetting(GuiSettings guiSettings) { } public UserPrefs(){ - this.setGuiSettings(500, 500, 0, 0); + this.setGuiSettings(1300, 800, 0, 0); } public void setGuiSettings(double width, double height, int x, int y) { diff --git a/src/main/java/seedu/malitio/model/history/InputAddHistory.java b/src/main/java/seedu/malitio/model/history/InputAddHistory.java new file mode 100644 index 000000000000..38b165fbecaf --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputAddHistory.java @@ -0,0 +1,19 @@ +package seedu.malitio.model.history; + +import seedu.malitio.logic.commands.DeleteCommand; + +//@@author A0129595N +public class InputAddHistory extends InputHistory { + + private Object task; + + public InputAddHistory(Object target) { + this.task = target; + this.commandForUndo = DeleteCommand.COMMAND_WORD; + } + + public Object getTask() { + return task; + } + +} diff --git a/src/main/java/seedu/malitio/model/history/InputClearHistory.java b/src/main/java/seedu/malitio/model/history/InputClearHistory.java new file mode 100644 index 000000000000..2afce80079ab --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputClearHistory.java @@ -0,0 +1,40 @@ +package seedu.malitio.model.history; + +import seedu.malitio.logic.commands.ClearCommand; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueEventList; +import seedu.malitio.model.task.UniqueFloatingTaskList; +//@@author A0129595N +public class InputClearHistory extends InputHistory{ + + UniqueFloatingTaskList originalFloatingTaskList = new UniqueFloatingTaskList(); + UniqueDeadlineList originalDeadlineList = new UniqueDeadlineList(); + UniqueEventList originalEventList = new UniqueEventList(); + UniqueTagList originalTagList = new UniqueTagList(); + + public InputClearHistory(UniqueFloatingTaskList task, UniqueDeadlineList deadline, + UniqueEventList event, UniqueTagList tag) { + this.originalFloatingTaskList.getInternalList().addAll(task.getInternalList()); + this.originalDeadlineList.getInternalList().addAll(deadline.getInternalList()); + this.originalEventList.getInternalList().addAll(event.getInternalList()); + this.originalTagList.getInternalList().addAll(tag.getInternalList()); + this.commandForUndo = ClearCommand.COMMAND_WORD; + } + + public UniqueFloatingTaskList getFloatingTask() { + return originalFloatingTaskList; + } + + public UniqueDeadlineList getDeadline() { + return originalDeadlineList; + } + + public UniqueEventList getEvent() { + return originalEventList; + } + + public UniqueTagList getTag() { + return originalTagList; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputCompleteHistory.java b/src/main/java/seedu/malitio/model/history/InputCompleteHistory.java new file mode 100644 index 000000000000..39c63fe285ca --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputCompleteHistory.java @@ -0,0 +1,17 @@ +package seedu.malitio.model.history; + +import seedu.malitio.logic.commands.UncompleteCommand; +//@@author A0129595N +public class InputCompleteHistory extends InputHistory { + + Object taskToUncomplete; + + public InputCompleteHistory(Object taskToUncomplete) { + this.taskToUncomplete = taskToUncomplete; + this.commandForUndo = UncompleteCommand.COMMAND_WORD; + } + + public Object getTask() { + return taskToUncomplete; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputDeleteHistory.java b/src/main/java/seedu/malitio/model/history/InputDeleteHistory.java new file mode 100644 index 000000000000..2ec203057933 --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputDeleteHistory.java @@ -0,0 +1,81 @@ +package seedu.malitio.model.history; + +import javafx.collections.ObservableList; +import seedu.malitio.logic.commands.AddCommand; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.DateTime; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.Event; +import seedu.malitio.model.task.FloatingTask; +import seedu.malitio.model.task.Name; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +//@@author A0129595N +public class InputDeleteHistory extends InputHistory { + private Object task; + private int initialPositionOfFloatingTask = -1; + + /** + * Constructor for the InputDeleteHistory for deletion of floating task. + * Will change the variable initialPositionOfFloatingTask to ensure that undo-ing a delete + * command will insert the floating task back to its original index. + * + * @param target + * task to be deleted + * @param observableList + * list of floating task from the model to extract the position + * of the floating task in the list before it is deleted + */ + public InputDeleteHistory(Object target, ObservableList observableList) { + this.commandForUndo = AddCommand.COMMAND_WORD; + String name = ((ReadOnlyFloatingTask) target).getName().fullName; + UniqueTagList tags = ((ReadOnlyFloatingTask) target).getTags(); + this.initialPositionOfFloatingTask = observableList.indexOf(target); + this.task = new FloatingTask(new Name(name), new UniqueTagList(tags)); + } + + /** + * Constructor for the InputDeleteHistory for deletion of deadline or event. + * Will not change the variable initialPositionOfFloatingTask + * + * @param target + * deadline/event to be deleted + */ + public InputDeleteHistory(Object target) { + String name, due, start, end; + UniqueTagList tags; + this.commandForUndo = AddCommand.COMMAND_WORD; + try { + if (isDeadline(target)) { + name = ((Deadline) target).getName().fullName; + due = ((Deadline) target).getDue().toString(); + tags = ((Deadline) target).getTags(); + this.task = new Deadline(new Name(name), new DateTime(due), new UniqueTagList(tags)); + } else { + name = ((Event) target).getName().fullName; + start = ((Event) target).getStart().toString(); + end = ((Event) target).getEnd().toString(); + tags = ((Event) target).getTags(); + this.task = new Event(new Name(name), new DateTime(start), new DateTime(end), new UniqueTagList(tags)); + } + } catch (Exception e) { + assert false : "Not possible"; + } + } + + private boolean isDeadline(Object target) { + return target instanceof ReadOnlyDeadline; + } + + public Object getTask() { + return task; + } + + /** + * @return -1 if the task is a deadline/event or a non-negative number if task is a floating task + */ + public int getPositionOfFloatingTask() { + return initialPositionOfFloatingTask; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputEditHistory.java b/src/main/java/seedu/malitio/model/history/InputEditHistory.java new file mode 100644 index 000000000000..ab39d82462db --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputEditHistory.java @@ -0,0 +1,81 @@ +package seedu.malitio.model.history; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.logic.commands.EditCommand; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.DateTime; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.Event; +import seedu.malitio.model.task.FloatingTask; +import seedu.malitio.model.task.Name; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +//@@author A0129595N +public class InputEditHistory extends InputHistory { + + private Object taskToEdit; + + private Object editedTask; + + public InputEditHistory(Object edited, Object beforeEdit) { + this.commandForUndo = EditCommand.COMMAND_WORD; + this.taskToEdit = edited; + if (isFloatingTask(edited)) { + createEditedFloatingTask(beforeEdit); + } else if (isDeadline(edited)) { + createEditedDeadline(beforeEdit); + } else { + createEditedEvent(beforeEdit); + } + } + + + private void createEditedEvent(Object beforeEdit) { + String name = ((Event)beforeEdit).getName().fullName; + String start = ((Event)beforeEdit).getStart().toString(); + String end = ((Event)beforeEdit).getEnd().toString(); + UniqueTagList tags = ((Event)beforeEdit).getTags(); + try { + this.editedTask = new Event(new Name(name), new DateTime(start), new DateTime(end), tags); + } catch (IllegalValueException e) { + assert false: "not possible"; + } + } + + + private void createEditedDeadline(Object beforeEdit) { + String name = ((ReadOnlyDeadline) beforeEdit).getName().fullName; + String due = ((ReadOnlyDeadline) beforeEdit).getDue().toString(); + UniqueTagList tags = ((ReadOnlyDeadline) beforeEdit).getTags(); + try { + this.editedTask = new Deadline(new Name(name), new DateTime(due), tags); + } catch (IllegalValueException e) { + assert false : "not possible"; + } + } + + + private void createEditedFloatingTask(Object beforeEdit) { + String name = ((ReadOnlyFloatingTask) beforeEdit).getName().fullName; + UniqueTagList tags = ((ReadOnlyFloatingTask) beforeEdit).getTags(); + this.editedTask = new FloatingTask(new Name(name), tags); + } + + + private boolean isDeadline(Object edited) { + return edited instanceof Deadline; + } + + private boolean isFloatingTask(Object edited) { + return edited instanceof FloatingTask; + } + + public Object getTaskToEdit() { + return taskToEdit; + } + + public Object getEditedTask() { + return editedTask; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputHistory.java b/src/main/java/seedu/malitio/model/history/InputHistory.java new file mode 100644 index 000000000000..e5be95b65033 --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputHistory.java @@ -0,0 +1,11 @@ +package seedu.malitio.model.history; + +//@@author A0129595N +public abstract class InputHistory { + + protected String commandForUndo; + + public String getUndoCommand() { + return commandForUndo; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputMarkHistory.java b/src/main/java/seedu/malitio/model/history/InputMarkHistory.java new file mode 100644 index 000000000000..46d9e80aed22 --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputMarkHistory.java @@ -0,0 +1,18 @@ +package seedu.malitio.model.history; + +import seedu.malitio.logic.commands.UnmarkCommand; + +//@@author A0129595N +public class InputMarkHistory extends InputHistory { + + Object taskToMark; + + public InputMarkHistory(Object taskToMark) { + this.commandForUndo = UnmarkCommand.COMMAND_WORD; + this.taskToMark = taskToMark; + } + + public Object getTask() { + return taskToMark; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputUncompleteHistory.java b/src/main/java/seedu/malitio/model/history/InputUncompleteHistory.java new file mode 100644 index 000000000000..0426c837ec80 --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputUncompleteHistory.java @@ -0,0 +1,17 @@ +package seedu.malitio.model.history; + +import seedu.malitio.logic.commands.CompleteCommand; +//@@author A0129595N +public class InputUncompleteHistory extends InputHistory { + + Object taskToComplete; + + public InputUncompleteHistory(Object taskToComplete) { + this.taskToComplete = taskToComplete; + this.commandForUndo = CompleteCommand.COMMAND_WORD; + } + + public Object getTask() { + return taskToComplete; + } +} diff --git a/src/main/java/seedu/malitio/model/history/InputUnmarkHistory.java b/src/main/java/seedu/malitio/model/history/InputUnmarkHistory.java new file mode 100644 index 000000000000..202635015d4a --- /dev/null +++ b/src/main/java/seedu/malitio/model/history/InputUnmarkHistory.java @@ -0,0 +1,17 @@ +package seedu.malitio.model.history; + +import seedu.malitio.logic.commands.MarkCommand; +//@@author A0129595N +public class InputUnmarkHistory extends InputHistory { + + Object taskToUnmark; + + public InputUnmarkHistory(Object taskToUnmark) { + this.commandForUndo = MarkCommand.COMMAND_WORD; + this.taskToUnmark = taskToUnmark; + } + + public Object getTask() { + return taskToUnmark; + } +} diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/malitio/model/tag/Tag.java similarity index 91% rename from src/main/java/seedu/address/model/tag/Tag.java rename to src/main/java/seedu/malitio/model/tag/Tag.java index 5bcffdb5ddf1..3468d63c1f1d 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/seedu/malitio/model/tag/Tag.java @@ -1,10 +1,10 @@ -package seedu.address.model.tag; +package seedu.malitio.model.tag; -import seedu.address.commons.exceptions.IllegalValueException; +import seedu.malitio.commons.exceptions.IllegalValueException; /** - * Represents a Tag in the address book. + * Represents a Tag in the malitio. * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)} */ public class Tag { diff --git a/src/main/java/seedu/address/model/tag/UniqueTagList.java b/src/main/java/seedu/malitio/model/tag/UniqueTagList.java similarity index 96% rename from src/main/java/seedu/address/model/tag/UniqueTagList.java rename to src/main/java/seedu/malitio/model/tag/UniqueTagList.java index 76fb7ff3dc5d..c1cddb6967fe 100644 --- a/src/main/java/seedu/address/model/tag/UniqueTagList.java +++ b/src/main/java/seedu/malitio/model/tag/UniqueTagList.java @@ -1,9 +1,9 @@ -package seedu.address.model.tag; +package seedu.malitio.model.tag; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.commons.exceptions.DuplicateDataException; +import seedu.malitio.commons.exceptions.DuplicateDataException; +import seedu.malitio.commons.util.CollectionUtil; import java.util.*; diff --git a/src/main/java/seedu/malitio/model/task/DateTime.java b/src/main/java/seedu/malitio/model/task/DateTime.java new file mode 100644 index 000000000000..387c6112d701 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/DateTime.java @@ -0,0 +1,50 @@ +package seedu.malitio.model.task; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.logic.parser.DateParser; + +/** + * Represents a date and time of an event or deadline + */ +//@@author a0126633j +public class DateTime { + public static final String MESSAGE_DATETIME_CONSTRAINTS = "Unrecognised date and time!"; + + private Date date; + + private static DateFormat outputFormatter = new SimpleDateFormat("dd-MMM-yyyy, HH:mm (EEE)"); + + /** + * Converts the string that contains date information into Date + * + * @throws IllegalValueException if the format of date is unrecognised + */ + public DateTime(String date) throws IllegalValueException { + + this.date = DateParser.parse(date); + if (this.date == null) { + throw new IllegalValueException(MESSAGE_DATETIME_CONSTRAINTS); + } + } + + public String toString() { + String newDateString = outputFormatter.format(date); + return newDateString; + } + + public int compareTo(DateTime dateTime) { + return date.compareTo(dateTime.getDate()); + } + + public int compareTo(Date date) { + return this.date.compareTo(date); + } + + public Date getDate() { + return date; + } +} diff --git a/src/main/java/seedu/malitio/model/task/Deadline.java b/src/main/java/seedu/malitio/model/task/Deadline.java new file mode 100644 index 000000000000..f4affbc75cb2 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/Deadline.java @@ -0,0 +1,101 @@ +package seedu.malitio.model.task; + +import java.util.Objects; + +import seedu.malitio.model.tag.UniqueTagList; + + +public class Deadline implements ReadOnlyDeadline{ + + private Name name; + private DateTime due; + private UniqueTagList tags; + private boolean completed; + private boolean marked; + + /** + * Constructor for deadlines. + */ + public Deadline(Name name, DateTime due, UniqueTagList tags) { + this.name = name; + this.due = due; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + this.completed = false; + this.marked = false; + } + + public Deadline(Name name, DateTime due, boolean completed, boolean marked, UniqueTagList tags) { + this.name = name; + this.due = due; + this.completed = completed; + this.marked = marked; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + } + + /** + * Copy constructor. + */ + public Deadline(ReadOnlyDeadline source) { + this(source.getName(), source.getDue(), source.getTags()); + this.completed = source.getCompleted(); + this.marked = source.isMarked(); + } + + + @Override + public Name getName() { + return name; + } + + @Override + public DateTime getDue() { + return due; + } + + @Override + public UniqueTagList getTags() { + return new UniqueTagList(tags); + } + + /** + * Replaces this deadline's tags with the tags in the argument tag list. + */ + public void setTags(UniqueTagList replacement) { + tags.setTags(replacement); + } + + public boolean getCompleted() { + return completed; + } + + public void setCompleted(boolean complete) { + this.completed = complete; + } + + public boolean isMarked() { + return marked; + } + + public void setMarked(boolean marked) { + this.marked = marked; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ReadOnlyDeadline// instanceof handles nulls + && this.isSameStateAs((ReadOnlyDeadline) other)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(name, due, tags); + } + + @Override + public String toString() { + return getAsText(); + } + +} diff --git a/src/main/java/seedu/malitio/model/task/Event.java b/src/main/java/seedu/malitio/model/task/Event.java new file mode 100644 index 000000000000..ba315b3ee7ac --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/Event.java @@ -0,0 +1,117 @@ +package seedu.malitio.model.task; + +import java.util.Objects; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.UniqueTagList; + +public class Event implements ReadOnlyEvent { + private Name name; + private DateTime start; + private DateTime end; + private UniqueTagList tags; + private boolean marked; + + public static final String MESSAGE_INVALID_EVENT = "Event must start before it ends!"; + + /** + * Constructor for events. + */ + public Event(Name name, DateTime start, DateTime end, UniqueTagList tags) + throws IllegalValueException { + + if(!isValidEvent(start, end)) { + throw new IllegalValueException(MESSAGE_INVALID_EVENT); + } + this.name = name; + this.start = start; + this.end = end; + this.tags = tags; + this.marked = false; + } + + public Event(Name name, DateTime start, DateTime end, boolean marked, UniqueTagList tags) + throws IllegalValueException { + + if(!isValidEvent(start, end)) { + throw new IllegalValueException(MESSAGE_INVALID_EVENT); + } + this.name = name; + this.start = start; + this.end = end; + this.marked = marked; + this.tags = tags; + this.marked = false; + } + + /** + * Copy constructor. + * @throws IllegalValueException + */ + public Event(ReadOnlyEvent source) throws IllegalValueException { + this(source.getName(), source.getStart(), source.getEnd(), source.getTags()); + this.marked = source.isMarked(); + } + + @Override + public Name getName() { + return name; + } + + @Override + public DateTime getStart() { + return start; + } + + @Override + public DateTime getEnd() { + return end; + } + + + @Override + public UniqueTagList getTags() { + return new UniqueTagList(tags); + } + + /** + * Replaces this event's tags with the tags in the argument tag list. + */ + public void setTags(UniqueTagList replacement) { + tags.setTags(replacement); + } + + public boolean isMarked() { + return marked; + } + + public void setMarked(boolean marked) { + this.marked = marked; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ReadOnlyEvent// instanceof handles nulls + && this.isSameStateAs((ReadOnlyEvent) other)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(name, start, end, tags); + } + + @Override + public String toString() { + return getAsText(); + } + + private static boolean isValidEvent(DateTime start, DateTime end) { + if (end.compareTo(start) > 0) { + return true; + } + return false; + } + +} diff --git a/src/main/java/seedu/malitio/model/task/FloatingTask.java b/src/main/java/seedu/malitio/model/task/FloatingTask.java new file mode 100644 index 000000000000..bbbddd365310 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/FloatingTask.java @@ -0,0 +1,94 @@ +package seedu.malitio.model.task; + +import java.util.Objects; + +import seedu.malitio.commons.util.CollectionUtil; +import seedu.malitio.model.tag.UniqueTagList; + +public class FloatingTask implements ReadOnlyFloatingTask { + + private Name name; + private boolean completed; + private boolean marked; + private UniqueTagList tags; + + /** + * Constructor for floating tasks. + */ + public FloatingTask(Name name, UniqueTagList tags) { + assert !CollectionUtil.isAnyNull(name, tags); + this.name = name; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + this.completed = false; + this.marked = false; + } + + public FloatingTask(Name name, boolean completed, boolean marked, UniqueTagList tags) { + assert !CollectionUtil.isAnyNull(name, tags); + this.name = name; + this.completed = completed; + this.marked = marked; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + } + + /** + * Copy constructor. + */ + public FloatingTask(ReadOnlyFloatingTask source) { + this(source.getName(), source.getTags()); + this.completed = source.getCompleted(); + this.marked = source.isMarked(); + } + + @Override + public Name getName() { + return name; + } + + @Override + public UniqueTagList getTags() { + return new UniqueTagList(tags); + } + + /** + * Replaces this task's tags with the tags in the argument tag list. + */ + public void setTags(UniqueTagList replacement) { + tags.setTags(replacement); + } + + public boolean getCompleted() { + return this.completed; + } + + public void setCompleted(boolean complete) { + this.completed = complete; + } + + public boolean isMarked() { + return this.marked; + } + + public void setMarked(boolean marked) { + this.marked = marked; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ReadOnlyFloatingTask // instanceof handles nulls + && this.isSameStateAs((ReadOnlyFloatingTask) other)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(name, tags); + } + + @Override + public String toString() { + return getAsText(); + } + +} diff --git a/src/main/java/seedu/malitio/model/task/Name.java b/src/main/java/seedu/malitio/model/task/Name.java new file mode 100644 index 000000000000..63095d0d33c4 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/Name.java @@ -0,0 +1,37 @@ +package seedu.malitio.model.task; + +/** + * Represents a Task's name in the Malitio. + * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} + */ +public class Name { + + public final String fullName; + + /** + * Validates given name. + */ + public Name(String name) { + assert name != null; + name = name.trim(); + this.fullName = name; + } + + @Override + public String toString() { + return fullName; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Name // instanceof handles nulls + && this.fullName.equals(((Name) other).fullName)); // state check + } + + @Override + public int hashCode() { + return fullName.hashCode(); + } + +} diff --git a/src/main/java/seedu/malitio/model/task/ReadOnlyDeadline.java b/src/main/java/seedu/malitio/model/task/ReadOnlyDeadline.java new file mode 100644 index 000000000000..3cea24512b8b --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/ReadOnlyDeadline.java @@ -0,0 +1,64 @@ +package seedu.malitio.model.task; +import seedu.malitio.model.tag.UniqueTagList; + +/** + * A read-only immutable interface for a Deadline in Malitio. + * Implementations should guarantee: details are present and not null, field values are validated. + * @@ Annabel Eng A0129595N + */ + +public interface ReadOnlyDeadline { + + Name getName(); + DateTime getDue(); + boolean getCompleted(); + void setCompleted(boolean complete); + boolean isMarked(); + void setMarked(boolean marked); + + /** + * The returned TagList is a deep copy of the internal TagList, + * changes on the returned list will not affect the task's internal tags. + */ + UniqueTagList getTags(); + + /** + * Returns true if both have the same state. (interfaces cannot override .equals) + */ + default boolean isSameStateAs(ReadOnlyDeadline other) { + return other == this // short circuit if same object + || (other != null // this is first to avoid NPE below + && other.getName().equals(this.getName()) + && other.getDue().toString().equals(this.getDue().toString()) //state checks here onwards + ); + } + + /** + * Formats the task as text, showing all contact details. + */ + default String getAsText() { + final StringBuilder builder = new StringBuilder(); + builder.append("Deadline: ") + .append(getName()) + .append(" Due: ") + .append(getDue()) + .append(" Tags: "); + getTags().forEach(builder::append); + return builder.toString(); + } + + /** + * Returns a string representation of this Task's tags + */ + default String tagsString() { + final StringBuffer buffer = new StringBuffer(); + final String separator = ", "; + getTags().forEach(tag -> buffer.append(tag).append(separator)); + if (buffer.length() == 0) { + return ""; + } else { + return buffer.substring(0, buffer.length() - separator.length()); + } + } +} + diff --git a/src/main/java/seedu/malitio/model/task/ReadOnlyEvent.java b/src/main/java/seedu/malitio/model/task/ReadOnlyEvent.java new file mode 100644 index 000000000000..88cf45bc59a2 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/ReadOnlyEvent.java @@ -0,0 +1,68 @@ +package seedu.malitio.model.task; +import seedu.malitio.model.tag.UniqueTagList; + +/** + * A read-only immutable interface for a Deadline in Malitio. + * Implementations should guarantee: details are present and not null, field values are validated. + * @@ Annabel Eng A0129595N + * + */ + +public interface ReadOnlyEvent { + + Name getName(); + DateTime getStart(); + DateTime getEnd(); + boolean isMarked(); + void setMarked(boolean marked); + + /** + * The returned TagList is a deep copy of the internal TagList, + * changes on the returned list will not affect the event's internal tags. + */ + UniqueTagList getTags(); + + /** + * Returns true if both have the same state. (interfaces cannot override .equals) + */ + default boolean isSameStateAs(ReadOnlyEvent other) { + return other == this // short circuit if same object + || (other != null // this is first to avoid NPE below + && other.getName().equals(this.getName()) + && other.getStart().toString().equals(this.getStart().toString()) + && other.getEnd().toString().equals(this.getEnd().toString())//state checks here onwards + ); + } + + /** + * Formats the event as text, showing all contact details. + */ + default String getAsText() { + final StringBuilder builder = new StringBuilder(); + + builder.append("Event: ") + .append(getName()) + .append(" Start: ") + .append(getStart()) + .append(" End: ") + .append(getEnd()) + .append(" Tags: "); + getTags().forEach(builder::append); + return builder.toString(); + } + + /** + * Returns a string representation of this Event's tags + */ + default String tagsString() { + final StringBuffer buffer = new StringBuffer(); + final String separator = ", "; + getTags().forEach(tag -> buffer.append(tag).append(separator)); + if (buffer.length() == 0) { + return ""; + } else { + return buffer.substring(0, buffer.length() - separator.length()); + } + } +} + diff --git a/src/main/java/seedu/address/model/person/ReadOnlyPerson.java b/src/main/java/seedu/malitio/model/task/ReadOnlyFloatingTask.java similarity index 53% rename from src/main/java/seedu/address/model/person/ReadOnlyPerson.java rename to src/main/java/seedu/malitio/model/task/ReadOnlyFloatingTask.java index d45be4b5fe36..1679ddbe39a1 100644 --- a/src/main/java/seedu/address/model/person/ReadOnlyPerson.java +++ b/src/main/java/seedu/malitio/model/task/ReadOnlyFloatingTask.java @@ -1,55 +1,54 @@ -package seedu.address.model.person; +package seedu.malitio.model.task; -import seedu.address.model.tag.UniqueTagList; +import seedu.malitio.model.tag.UniqueTagList; /** - * A read-only immutable interface for a Person in the addressbook. + * A read-only immutable interface for a Task in Malitio. * Implementations should guarantee: details are present and not null, field values are validated. + * + * @@ Annabel Eng A0129595N */ -public interface ReadOnlyPerson { + +public interface ReadOnlyFloatingTask { Name getName(); - Phone getPhone(); - Email getEmail(); - Address getAddress(); + boolean getCompleted(); + void setCompleted(boolean complete); + boolean isMarked(); + void setMarked(boolean marked); + /** * The returned TagList is a deep copy of the internal TagList, - * changes on the returned list will not affect the person's internal tags. + * changes on the returned list will not affect the task's internal tags. */ UniqueTagList getTags(); /** * Returns true if both have the same state. (interfaces cannot override .equals) */ - default boolean isSameStateAs(ReadOnlyPerson other) { + + default boolean isSameStateAs(ReadOnlyFloatingTask other) { return other == this // short circuit if same object || (other != null // this is first to avoid NPE below && other.getName().equals(this.getName()) // state checks here onwards - && other.getPhone().equals(this.getPhone()) - && other.getEmail().equals(this.getEmail()) - && other.getAddress().equals(this.getAddress())); +); } /** - * Formats the person as text, showing all contact details. + * Formats the task as text, showing all contact details. */ default String getAsText() { final StringBuilder builder = new StringBuilder(); - builder.append(getName()) - .append(" Phone: ") - .append(getPhone()) - .append(" Email: ") - .append(getEmail()) - .append(" Address: ") - .append(getAddress()) - .append(" Tags: "); + builder.append("Task: ") + .append(getName()) + .append(" Tags: "); getTags().forEach(builder::append); return builder.toString(); } /** - * Returns a string representation of this Person's tags + * Returns a string representation of this Task's tags */ default String tagsString() { final StringBuffer buffer = new StringBuffer(); diff --git a/src/main/java/seedu/malitio/model/task/UniqueDeadlineList.java b/src/main/java/seedu/malitio/model/task/UniqueDeadlineList.java new file mode 100644 index 000000000000..8b01055fc221 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/UniqueDeadlineList.java @@ -0,0 +1,277 @@ +package seedu.malitio.model.task; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.malitio.commons.exceptions.DuplicateDataException; +import seedu.malitio.commons.util.CollectionUtil; +import java.util.*; + +/** + * A list of tasks that enforces uniqueness between its elements and does not + * allow nulls. + * + * Supports a minimal set of list operations. + * + * @see Task#equals(Object) + * @see CollectionUtil#elementsAreUnique(Collection) + */ + +public class UniqueDeadlineList implements Iterable { + + /** + * Signals that an operation would have violated the 'no duplicates' + * property of the list. + */ + public static class DuplicateDeadlineException extends DuplicateDataException { + protected DuplicateDeadlineException() { + super("Operation would result in duplicate deadlines"); + } + } + + /** + * Signals that an operation targeting a specified task in the list would + * fail because there is no such matching task in the list. + */ + public static class DeadlineNotFoundException extends Exception { + } + + public static class DeadlineCompletedException extends Exception { + } + + public static class DeadlineUncompletedException extends Exception { + } + + public static class DeadlineMarkedException extends Exception { + } + + public static class DeadlineUnmarkedException extends Exception { + } + + private final ObservableList internalList = FXCollections.observableArrayList(); + + /** + * Constructs empty TaskList. + */ + public UniqueDeadlineList() { + } + + /** + * Returns true if the list contains an equivalent task as the given + * argument. + */ + public boolean contains(ReadOnlyDeadline toCheck) { + assert toCheck != null; + return internalList.contains(toCheck); + } + + // @@author A0129595N + /** + * Returns true if the list contains an equivalent deadline as the given + * argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyDeadline toCheck) { + assert toCheck != null; + if (!internalList.contains(toCheck)) { + return false; + } else { + int index = internalList.indexOf(toCheck); + if (toCheck.getTags().getInternalList().isEmpty()) { + return internalList.get(index).getTags().getInternalList().isEmpty(); + } else { + return internalList.get(index).getTags().getInternalList() + .containsAll(toCheck.getTags().getInternalList()); + } + } + } + + /** + * Adds a task to the list. + * + * @throws DuplicateDeadlineException + * if the task to add is a duplicate of an existing task in the + * list. + */ + public void add(Deadline toAdd) throws DuplicateDeadlineException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateDeadlineException(); + } + internalList.add(toAdd); + } + + /** + * Edits the specified deadline by deleting and re-adding of the edited + * (changed) deadline + * + * @param edited + * the edited deadline + * @param beforeEdit + * the original deadline + * @throws DuplicateDeadlineException + * @throws DeadlineNotFoundException + */ + public void edit(Deadline edited, ReadOnlyDeadline beforeEdit) + throws DuplicateDeadlineException, DeadlineNotFoundException { + assert edited != null; + assert beforeEdit != null; + if (containsWithTags(edited)) { + throw new DuplicateDeadlineException(); + } + + if (!contains(beforeEdit)) { + throw new DeadlineNotFoundException(); + } + + internalList.remove(beforeEdit); + internalList.add(edited); + } + + // @@author A0122460W + /** + * Complete the deadline in the list. + * + * @throws DeadlineNotFoundException + * if the deadline is not found. + * @throws DeadlineCompletedException + * if the deadline is already completed. + */ + public void complete(ReadOnlyDeadline deadlineToComplete) + throws DeadlineCompletedException, DeadlineNotFoundException { + assert deadlineToComplete != null; + + if (deadlineToComplete.getCompleted()) { + throw new DeadlineCompletedException(); + } + + if (!contains(deadlineToComplete)) { + throw new DeadlineNotFoundException(); + } + + deadlineToComplete.setCompleted(true); + updateDeadlineList(deadlineToComplete); + } + + /** + * Uncomplete the deadline in the list. + * + * @throws DeadlineNotFoundException + * if the deadline is not found. + * @throws DeadlineUncompletedException + * if the deadline is already uncompleted. + */ + public void uncomplete(ReadOnlyDeadline deadlineToComplete) + throws DeadlineUncompletedException, DeadlineNotFoundException { + assert deadlineToComplete != null; + + if (!deadlineToComplete.getCompleted()) { + throw new DeadlineUncompletedException(); + } + + if (!contains(deadlineToComplete)) { + throw new DeadlineNotFoundException(); + } + + deadlineToComplete.setCompleted(false); + updateDeadlineList(deadlineToComplete); + } + + // @@author A0153006W + /** + * Marks the deadline in the list. + * + * @throws DeadlineNotFoundException + * if the deadline doesn't exist. + * @throws DeadlineMarkedException + * if the deadline is already marked. + */ + public void mark(ReadOnlyDeadline taskToMark) throws DeadlineNotFoundException, DeadlineMarkedException { + if (taskToMark.isMarked()) { + throw new DeadlineMarkedException(); + } + + if (!contains(taskToMark)) { + throw new DeadlineNotFoundException(); + } + taskToMark.setMarked(true); + updateDeadlineList(taskToMark); + } + + /** + * Unmarks the task in the list. + * + * @throws DeadlineNotFoundException + * if the deadline doesn't exist. + * @throws DeadlineUnmarkedException + * if the deadline is already unmarked. + */ + public void unmark(ReadOnlyDeadline taskToUnmark) throws DeadlineNotFoundException, DeadlineUnmarkedException { + if (!taskToUnmark.isMarked()) { + throw new DeadlineUnmarkedException(); + } + + if (!contains(taskToUnmark)) { + throw new DeadlineNotFoundException(); + } + taskToUnmark.setMarked(false); + updateDeadlineList(taskToUnmark); + } + + // @@author + /* + * Updates Malitio + */ + private void updateDeadlineList(ReadOnlyDeadline deadlineToComplete) { + int indexToReplace = internalList.indexOf(deadlineToComplete); + internalList.remove(deadlineToComplete); + internalList.add(indexToReplace, (Deadline) deadlineToComplete); + } + + /** + * Removes the equivalent schedule from the list. + * + * @throws DeadlineNotFoundException + * if no such deadline could be found in the list. + */ + public boolean remove(ReadOnlyDeadline toRemove) throws DeadlineNotFoundException { + assert toRemove != null; + final boolean deadlineFoundAndDeleted = internalList.remove(toRemove); + if (!deadlineFoundAndDeleted) { + throw new DeadlineNotFoundException(); + } + return deadlineFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + // @@author + public void sort() { + Collections.sort(internalList, new Comparator() { + public int compare(Deadline e1, Deadline e2) { + if (e1.getDue() == null || e2.getDue() == null) + return 0; + return e1.getDue().compareTo(e2.getDue()); + } + }); + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueDeadlineList // instanceof handles + // nulls + && this.internalList.equals(((UniqueDeadlineList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/malitio/model/task/UniqueEventList.java b/src/main/java/seedu/malitio/model/task/UniqueEventList.java new file mode 100644 index 000000000000..f0a3cd328400 --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/UniqueEventList.java @@ -0,0 +1,214 @@ +package seedu.malitio.model.task; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.malitio.commons.exceptions.DuplicateDataException; +import seedu.malitio.commons.util.CollectionUtil; +import seedu.malitio.model.task.UniqueFloatingTaskList.FloatingTaskNotFoundException; + +import java.util.*; + +/** + * A list of tasks that enforces uniqueness between its elements and does not allow nulls. + * + * Supports a minimal set of list operations. + * + * @see Task#equals(Object) + * @see CollectionUtil#elementsAreUnique(Collection) + */ + +public class UniqueEventList implements Iterable { + + /** + * Signals that an operation would have violated the 'no duplicates' property of the list. + */ + public static class DuplicateEventException extends DuplicateDataException { + protected DuplicateEventException() { + super("Operation would result in duplicate events"); + } + } + + /** + * Signals that an operation targeting a specified task in the list would fail because + * there is no such matching task in the list. + */ + public static class EventNotFoundException extends Exception {} + + public static class EventMarkedException extends Exception {} + + public static class EventUnmarkedException extends Exception {} + + private final ObservableList internalList = FXCollections.observableArrayList(); + + /** + * Constructs empty EventList. + */ + public UniqueEventList() {} + + /** + * Returns true if the list contains an equivalent event as the given argument. + */ + public boolean contains(ReadOnlyEvent toCheck) { + assert toCheck != null; + return internalList.contains(toCheck); + } + //@@author A0129595N + /** + * Returns true if the list contains an equivalent event as the given + * argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyEvent toCheck) { + assert toCheck != null; + if (!internalList.contains(toCheck)) { + return false; + } else { + int index = internalList.indexOf(toCheck); + if (toCheck.getTags().getInternalList().isEmpty()) { + return internalList.get(index).getTags().getInternalList().isEmpty(); + } else { + return internalList.get(index).getTags().getInternalList() + .containsAll(toCheck.getTags().getInternalList()); + } + } + } + + /** + * Adds a task to the list. + * + * @throws DuplicateEventException + * if the event to add is a duplicate of an existing event in + * the list. + */ + public void add(Event toAdd) throws DuplicateEventException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateEventException(); + } + internalList.add(toAdd); + } + + /** + * Edits the specified event by deleting and re-adding of the edited + * (changed) event. + * + * @param edited + * the edited event + * @param beforeEdit + * the original event + * @throws DuplicateEventException + * @throws EventNotFoundException + */ + public void edit(Event edited, ReadOnlyEvent beforeEdit) throws DuplicateEventException, EventNotFoundException { + assert edited != null; + assert beforeEdit != null; + if (containsWithTags(edited)) { + throw new DuplicateEventException(); + } + + if (!contains(beforeEdit)) { + throw new EventNotFoundException(); + } + + internalList.remove(beforeEdit); + internalList.add(edited); + } + //@@author + + //@@author A0153006W + /** + * Marks the event in the list. + * + * @throws EventNotFoundException if the event doesn't exist. + * @throws EventMarkedException if the event is already marked. + */ + public void mark(ReadOnlyEvent taskToMark) + throws EventNotFoundException, EventMarkedException { + if (taskToMark.isMarked()) { + throw new EventMarkedException(); + } + + if (!contains(taskToMark)) { + throw new EventNotFoundException(); + } + taskToMark.setMarked(true); + updateEventList(taskToMark); + } + + /** + * Unmarks the task in the list. + * + * @throws EventNotFoundException if the event doesn't exist. + * @throws EventUnmarkedException if the event is already unmarked. + */ + public void unmark(ReadOnlyEvent taskToUnmark) + throws EventNotFoundException, EventUnmarkedException { + if (!taskToUnmark.isMarked()) { + throw new EventUnmarkedException(); + } + + if (!contains(taskToUnmark)) { + throw new EventNotFoundException(); + } + taskToUnmark.setMarked(false); + updateEventList(taskToUnmark); + } + + //@@author + /* + * Updates Malitio + */ + private void updateEventList(ReadOnlyEvent eventToComplete) { + int indexToReplace = internalList.indexOf(eventToComplete); + internalList.remove(eventToComplete); + internalList.add(indexToReplace, (Event) eventToComplete); + } + + /** + * Removes the equivalent schedule from the list. + * + * @throws FloatingTaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyEvent toRemove) throws EventNotFoundException { + assert toRemove != null; + final boolean eventFoundAndDeleted = internalList.remove(toRemove); + if (!eventFoundAndDeleted) { + throw new EventNotFoundException(); + } + return eventFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + //@@author + public void sort() { + Collections.sort(internalList, new Comparator() { + public int compare(Event e1, Event e2) { + if (e1.getStart() == null || e2.getStart() == null) + return 0; + return e1.getStart().compareTo(e2.getStart()); + } + }); + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueEventList // instanceof handles nulls + && this.internalList.equals( + ((UniqueEventList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + +} + diff --git a/src/main/java/seedu/malitio/model/task/UniqueFloatingTaskList.java b/src/main/java/seedu/malitio/model/task/UniqueFloatingTaskList.java new file mode 100644 index 000000000000..554ce08e472f --- /dev/null +++ b/src/main/java/seedu/malitio/model/task/UniqueFloatingTaskList.java @@ -0,0 +1,263 @@ +package seedu.malitio.model.task; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.malitio.commons.exceptions.DuplicateDataException; +import seedu.malitio.commons.util.CollectionUtil; + +import java.util.*; + +/** + * A list of tasks that enforces uniqueness between its elements and does not allow nulls. + * + * Supports a minimal set of list operations. + * + * @see Task#equals(Object) + * @see CollectionUtil#elementsAreUnique(Collection) + */ + +public class UniqueFloatingTaskList implements Iterable { + + /** + * Signals that an operation would have violated the 'no duplicates' property of the list. + */ + public static class DuplicateFloatingTaskException extends DuplicateDataException { + protected DuplicateFloatingTaskException() { + super("Operation would result in duplicate floating tasks"); + } + } + + /** + * Signals that an operation targeting a specified task in the list would fail because + * there is no such matching task in the list. + */ + public static class FloatingTaskNotFoundException extends Exception {} + + public static class FloatingTaskCompletedException extends Exception {} + + public static class FloatingTaskUncompletedException extends Exception {} + + public static class FloatingTaskMarkedException extends Exception {} + + public static class FloatingTaskUnmarkedException extends Exception {} + + private final ObservableList internalList = FXCollections.observableArrayList(); + + /** + * Constructs empty TaskList. + */ + public UniqueFloatingTaskList() {} + + /** + * Returns true if the list contains an equivalent task as the given argument. + */ + public boolean contains(ReadOnlyFloatingTask toCheck) { + assert toCheck != null; + return internalList.contains(toCheck); + } + //@@author A0129595N + /** + * Returns true if the list contains an equivalent task as the given + * argument as well as identical tag(s). + */ + public boolean containsWithTags(ReadOnlyFloatingTask toCheck) { + assert toCheck != null; + if (!internalList.contains(toCheck)) { + return false; + } else { + int index = internalList.indexOf(toCheck); + if (toCheck.getTags().getInternalList().isEmpty()) { + return internalList.get(index).getTags().getInternalList().isEmpty(); + } else { + return internalList.get(index).getTags().getInternalList() + .containsAll(toCheck.getTags().getInternalList()); + } + } + } + + /** + * Adds a floating task to the list. + * + * @throws DuplicateFloatingTaskException + * if the task to add is a duplicate of an existing task in the + * list. + */ + public void add(FloatingTask toAdd) throws DuplicateFloatingTaskException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateFloatingTaskException(); + } + internalList.add(toAdd); + } + + /** + * Adds a floating task to the list at the given index + * + * @param toAdd + * @param index + * @throws DuplicateFloatingTaskException + * if the task to add is a duplicate of an existing task in the + * list. + */ + public void add(FloatingTask toAdd, int index) throws DuplicateFloatingTaskException { + assert toAdd != null; + assert index >= 0; + if (contains(toAdd)) { + throw new DuplicateFloatingTaskException(); + } + internalList.add(index, toAdd); + } + + /** + * Edits the specified floating task by deleting and re-adding of the edited + * (changed) floating task + * + * @param edited + * the edited floating task + * @param beforeEdit + * the original floating task + * @throws DuplicateFloatingTaskException + * @throws FloatingTaskNotFoundException + */ + public void edit(FloatingTask edited, ReadOnlyFloatingTask beforeEdit) + throws DuplicateFloatingTaskException, FloatingTaskNotFoundException { + assert edited != null; + assert beforeEdit != null; + if (containsWithTags(edited)) { + throw new DuplicateFloatingTaskException(); + } + + if (!contains(beforeEdit)) { + throw new FloatingTaskNotFoundException(); + } + + int indexToReplace = internalList.indexOf(beforeEdit); + internalList.remove(beforeEdit); + internalList.add(indexToReplace, edited); + } + + //@@author A0122460W + /** + * Completes the task in the list. + * + * @throws FloatingTaskCompletedException if the task is already completed. + * @throws FloatingTaskNotFoundException if the floating task doesn't exist. + */ + public void complete(ReadOnlyFloatingTask toComplete) throws FloatingTaskCompletedException, FloatingTaskNotFoundException { + assert toComplete != null; + if (toComplete.getCompleted()) { + throw new FloatingTaskCompletedException(); + } + + if (!contains(toComplete)) { + throw new FloatingTaskNotFoundException(); + } + toComplete.setCompleted(true); + updateFloatingTaskList(toComplete); + } + + /** + * Marks the task in the list. + * + * @throws FloatingTaskUncompletedException if the task is already not completed. + * @throws FloatingTaskNotFoundException if the floating task doesn't exist. + */ + public void uncomplete(ReadOnlyFloatingTask toUncomplete) throws FloatingTaskUncompletedException, FloatingTaskNotFoundException { + assert toUncomplete != null; + if (!toUncomplete.getCompleted()) { + throw new FloatingTaskUncompletedException(); + } + + if (!contains(toUncomplete)) { + throw new FloatingTaskNotFoundException(); + } + toUncomplete.setCompleted(false); + updateFloatingTaskList(toUncomplete); + } + + //@@author A0153006W + /** + * Marks the task in the list. + * + * @throws FloatingTaskNotFoundException if the task doesn't exist. + * @throws FloatingTaskMarkedException if the task is already marked. + */ + public void mark(ReadOnlyFloatingTask taskToMark) + throws FloatingTaskNotFoundException, FloatingTaskMarkedException { + if (taskToMark.isMarked()) { + throw new FloatingTaskMarkedException(); + } + + if (!contains(taskToMark)) { + throw new FloatingTaskNotFoundException(); + } + taskToMark.setMarked(true); + updateFloatingTaskList(taskToMark); + } + + /** + * Unmarks the task in the list. + * + * @throws FloatingTaskNotFoundException if the task doesn't exist. + * @throws FloatingTaskUnmarkedException if the task is already unmarked. + */ + public void unmark(ReadOnlyFloatingTask taskToUnmark) + throws FloatingTaskNotFoundException, FloatingTaskUnmarkedException { + if (!taskToUnmark.isMarked()) { + throw new FloatingTaskUnmarkedException(); + } + + if (!contains(taskToUnmark)) { + throw new FloatingTaskNotFoundException(); + } + taskToUnmark.setMarked(false); + updateFloatingTaskList(taskToUnmark); + } + + /** + * Updates Malitio + */ + private void updateFloatingTaskList(ReadOnlyFloatingTask toComplete) { + int indexToReplace = internalList.indexOf(toComplete); + internalList.remove(toComplete); + internalList.add(indexToReplace, (FloatingTask) toComplete); + } + + //@@ author + /** + * Removes the equivalent task from the list. + * + * @throws FloatingTaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyFloatingTask toRemove) throws FloatingTaskNotFoundException { + assert toRemove != null; + final boolean taskFoundAndDeleted = internalList.remove(toRemove); + if (!taskFoundAndDeleted) { + throw new FloatingTaskNotFoundException(); + } + return taskFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueFloatingTaskList // instanceof handles nulls + && this.internalList.equals( + ((UniqueFloatingTaskList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/malitio/storage/JsonUserPrefsStorage.java similarity index 90% rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java rename to src/main/java/seedu/malitio/storage/JsonUserPrefsStorage.java index 1efa8288e4f6..3e2b5322fd66 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/seedu/malitio/storage/JsonUserPrefsStorage.java @@ -1,9 +1,9 @@ -package seedu.address.storage; +package seedu.malitio.storage; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.UserPrefs; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.model.UserPrefs; import java.io.File; import java.io.IOException; diff --git a/src/main/java/seedu/malitio/storage/MalitioStorage.java b/src/main/java/seedu/malitio/storage/MalitioStorage.java new file mode 100644 index 000000000000..23cbc6d0d4c9 --- /dev/null +++ b/src/main/java/seedu/malitio/storage/MalitioStorage.java @@ -0,0 +1,44 @@ +package seedu.malitio.storage; + +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.model.ReadOnlyMalitio; + +import java.io.IOException; +import java.util.Optional; + +/** + * Represents a storage for {@link seedu.malitio.model.Malitio}. + */ +public interface MalitioStorage { + + /** + * Returns the file path of the data file. + */ + String getMalitioFilePath(); + + /** + * Returns malitio data as a {@link ReadOnlyMalitio}. + * Returns {@code Optional.empty()} if storage file is not found. + * @throws DataConversionException if the data in storage is not in the expected format. + * @throws IOException if there was any problem when reading from the storage. + */ + Optional readMalitio() throws DataConversionException, IOException; + + /** + * @see #getMalitioFilePath() + */ + Optional readMalitio(String filePath) throws DataConversionException, IOException; + + /** + * Saves the given {@link ReadOnlyMalitio} to the storage. + * @param malitio cannot be null. + * @throws IOException if there was any problem writing to the file. + */ + void saveMalitio(ReadOnlyMalitio malitio) throws IOException; + + /** + * @see #saveMalitio(ReadOnlyMalitio) + */ + void saveMalitio(ReadOnlyMalitio malitio, String filePath) throws IOException; + +} diff --git a/src/main/java/seedu/malitio/storage/Storage.java b/src/main/java/seedu/malitio/storage/Storage.java new file mode 100644 index 000000000000..e0d4fd84e237 --- /dev/null +++ b/src/main/java/seedu/malitio/storage/Storage.java @@ -0,0 +1,39 @@ +package seedu.malitio.storage; + +import seedu.malitio.commons.events.model.MalitioChangedEvent; +import seedu.malitio.commons.events.storage.DataSavingExceptionEvent; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.UserPrefs; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Optional; + +/** + * API of the Storage component + */ +public interface Storage extends MalitioStorage, UserPrefsStorage { + + @Override + Optional readUserPrefs() throws DataConversionException, IOException; + + @Override + void saveUserPrefs(UserPrefs userPrefs) throws IOException; + + @Override + String getMalitioFilePath(); + + @Override + Optional readMalitio() throws DataConversionException, IOException; + + @Override + void saveMalitio(ReadOnlyMalitio malitio) throws IOException; + + /** + * Saves the current version of the malitio to the hard disk. + * Creates the data file if it is missing. + * Raises {@link DataSavingExceptionEvent} if there was an error during saving. + */ + void handleMalitioChangedEvent(MalitioChangedEvent abce); +} diff --git a/src/main/java/seedu/malitio/storage/StorageManager.java b/src/main/java/seedu/malitio/storage/StorageManager.java new file mode 100644 index 000000000000..3e45dadff80f --- /dev/null +++ b/src/main/java/seedu/malitio/storage/StorageManager.java @@ -0,0 +1,120 @@ +package seedu.malitio.storage; + +import com.google.common.eventbus.Subscribe; + +import seedu.malitio.commons.core.ComponentManager; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.model.MalitioChangedEvent; +import seedu.malitio.commons.events.storage.DataSavingExceptionEvent; +import seedu.malitio.commons.events.storage.DataStorageFileChangedEvent; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.UserPrefs; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.logging.Logger; + +/** + * Manages storage of Malitio data in local storage. + */ +public class StorageManager extends ComponentManager implements Storage { + + private static final Logger logger = LogsCenter.getLogger(StorageManager.class); + private MalitioStorage malitioStorage; + private UserPrefsStorage userPrefsStorage; + + public StorageManager(MalitioStorage malitioStorage, UserPrefsStorage userPrefsStorage) { + super(); + this.malitioStorage = malitioStorage; + this.userPrefsStorage = userPrefsStorage; + } + + public StorageManager(String malitioFilePath, String userPrefsFilePath) { + this(new XmlMalitioStorage(malitioFilePath), new JsonUserPrefsStorage(userPrefsFilePath)); + } + + // ================ UserPrefs methods ============================== + + @Override + public Optional readUserPrefs() throws DataConversionException, IOException { + return userPrefsStorage.readUserPrefs(); + } + + @Override + public void saveUserPrefs(UserPrefs userPrefs) throws IOException { + userPrefsStorage.saveUserPrefs(userPrefs); + } + + + // ================ Malitio methods ============================== + + @Override + public String getMalitioFilePath() { + return malitioStorage.getMalitioFilePath(); + } + + @Override + public Optional readMalitio() throws DataConversionException, IOException { + return readMalitio(malitioStorage.getMalitioFilePath()); + } + + @Override + public Optional readMalitio(String filePath) throws DataConversionException, IOException { + logger.fine("Attempting to read data from file: " + filePath); + return malitioStorage.readMalitio(filePath); + } + + @Override + public void saveMalitio(ReadOnlyMalitio malitio) throws IOException { + saveMalitio(malitio, malitioStorage.getMalitioFilePath()); + } + + @Override + public void saveMalitio(ReadOnlyMalitio malitio, String filePath) throws IOException { + logger.fine("Attempting to write to data file: " + filePath); + malitioStorage.saveMalitio(malitio, filePath); + } + + + @Override + @Subscribe + public void handleMalitioChangedEvent(MalitioChangedEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Local data changed, saving to file")); + try { + saveMalitio(event.data, malitioStorage.getMalitioFilePath()); + } catch (IOException e) { + raise(new DataSavingExceptionEvent(e)); + } + } + + /** + * Stores the current data file in the new directory and deletes the old data file. + * @param event + * @throws DataConversionException + * @throws IOException + */ + //@@author a0126633j + @Subscribe + public void handleDataStorageFileChangedEvent(DataStorageFileChangedEvent event) throws DataConversionException, IOException { + String oldDataFilePath = malitioStorage.getMalitioFilePath(); + Optional dataToBeTransferred = malitioStorage.readMalitio(); + malitioStorage = new XmlMalitioStorage(event.dataFilePath); + + if(FileUtil.twoFilePathsAreEqual(oldDataFilePath, this.malitioStorage.getMalitioFilePath())) { + return; + } + + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Data storage file path changed, updating..")); + + try { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Old data file is being deleted.")); + FileUtil.deleteFile(oldDataFilePath); + } catch (IOException e) { + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Failed to delete old data file.")); + } + } +} diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/malitio/storage/UserPrefsStorage.java similarity index 73% rename from src/main/java/seedu/address/storage/UserPrefsStorage.java rename to src/main/java/seedu/malitio/storage/UserPrefsStorage.java index ad2dc935187c..df3e88aaeb36 100644 --- a/src/main/java/seedu/address/storage/UserPrefsStorage.java +++ b/src/main/java/seedu/malitio/storage/UserPrefsStorage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; +package seedu.malitio.storage; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.UserPrefs; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.model.UserPrefs; import java.io.IOException; import java.util.Optional; /** - * Represents a storage for {@link seedu.address.model.UserPrefs}. + * Represents a storage for {@link seedu.malitio.model.UserPrefs}. */ public interface UserPrefsStorage { @@ -20,7 +20,7 @@ public interface UserPrefsStorage { Optional readUserPrefs() throws DataConversionException, IOException; /** - * Saves the given {@link seedu.address.model.UserPrefs} to the storage. + * Saves the given {@link seedu.malitio.model.UserPrefs} to the storage. * @param userPrefs cannot be null. * @throws IOException if there was any problem writing to the file. */ diff --git a/src/main/java/seedu/malitio/storage/XmlAdaptedDeadline.java b/src/main/java/seedu/malitio/storage/XmlAdaptedDeadline.java new file mode 100644 index 000000000000..ec2a79fa57e3 --- /dev/null +++ b/src/main/java/seedu/malitio/storage/XmlAdaptedDeadline.java @@ -0,0 +1,68 @@ +package seedu.malitio.storage; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.DateTime; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.Name; +import seedu.malitio.model.task.ReadOnlyDeadline; + +public class XmlAdaptedDeadline { + + @XmlElement(required = true) + private String name; + @XmlElement(required = true) + private boolean completed; + @XmlElement(required = true) + private boolean marked; + @XmlElement(required = true) + private String due; + @XmlElement + private List tagged = new ArrayList<>(); + + /** + * No-arg constructor for JAXB use. + */ + public XmlAdaptedDeadline() {} + + + /** + * Converts a given Schedule into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedTask + */ + public XmlAdaptedDeadline(ReadOnlyDeadline source) { + name = source.getName().fullName; + due = source.getDue().toString(); + completed = source.getCompleted(); + marked = source.isMarked(); + tagged = new ArrayList<>(); + for (Tag tag : source.getTags()) { + tagged.add(new XmlAdaptedTag(tag)); + } + } + + /** + * Converts this jaxb-friendly adapted task object into the model's Task object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted Task + */ + public Deadline toModelType() throws IllegalValueException { + final List taskTags = new ArrayList<>(); + for (XmlAdaptedTag tag : tagged) { + taskTags.add(tag.toModelType()); + } + final Name name = new Name(this.name); + final DateTime due = new DateTime(this.due); + final boolean complete = this.completed; + final boolean marked = this.marked; + final UniqueTagList tags = new UniqueTagList(taskTags); + return new Deadline(name, due, complete, marked, tags); + } +} diff --git a/src/main/java/seedu/malitio/storage/XmlAdaptedEvent.java b/src/main/java/seedu/malitio/storage/XmlAdaptedEvent.java new file mode 100644 index 000000000000..970483ffd9f5 --- /dev/null +++ b/src/main/java/seedu/malitio/storage/XmlAdaptedEvent.java @@ -0,0 +1,68 @@ +package seedu.malitio.storage; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.DateTime; +import seedu.malitio.model.task.Event; +import seedu.malitio.model.task.Name; +import seedu.malitio.model.task.ReadOnlyEvent; + +public class XmlAdaptedEvent { + + @XmlElement(required = true) + private String name; + + + @XmlElement(required = true) + private String start; + + @XmlElement(required = true) + private String end; + + @XmlElement + private List tagged = new ArrayList<>(); + + /** + * No-arg constructor for JAXB use. + */ + public XmlAdaptedEvent() {} + + + /** + * Converts a given Schedule into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedTask + */ + public XmlAdaptedEvent(ReadOnlyEvent source) { + name = source.getName().fullName; + start = source.getStart().toString(); + end = source.getEnd().toString(); + tagged = new ArrayList<>(); + for (Tag tag : source.getTags()) { + tagged.add(new XmlAdaptedTag(tag)); + } + } + + /** + * Converts this jaxb-friendly adapted task object into the model's Task object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted Task + */ + public Event toModelType() throws IllegalValueException { + final List taskTags = new ArrayList<>(); + for (XmlAdaptedTag tag : tagged) { + taskTags.add(tag.toModelType()); + } + final Name name = new Name(this.name); + final DateTime start = new DateTime(this.start); + final DateTime end = new DateTime(this.end); + final UniqueTagList tags = new UniqueTagList(taskTags); + return new Event(name, start, end, tags); + } +} diff --git a/src/main/java/seedu/malitio/storage/XmlAdaptedFloatingTask.java b/src/main/java/seedu/malitio/storage/XmlAdaptedFloatingTask.java new file mode 100644 index 000000000000..6635309dea0b --- /dev/null +++ b/src/main/java/seedu/malitio/storage/XmlAdaptedFloatingTask.java @@ -0,0 +1,65 @@ +package seedu.malitio.storage; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; + +import javax.xml.bind.annotation.XmlElement; +import java.util.ArrayList; +import java.util.List; + +/** + * JAXB-friendly version of the Task. + */ +public class XmlAdaptedFloatingTask { + + @XmlElement(required = true) + private String name; + @XmlElement(required = true) + private boolean completed; + @XmlElement(required = true) + private boolean marked; + + + @XmlElement + private List tagged = new ArrayList<>(); + + /** + * No-arg constructor for JAXB use. + */ + public XmlAdaptedFloatingTask() {} + + + /** + * Converts a given Task into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedTask + */ + public XmlAdaptedFloatingTask(ReadOnlyFloatingTask source) { + name = source.getName().fullName; + completed = source.getCompleted(); + marked = source.isMarked(); + tagged = new ArrayList<>(); + for (Tag tag : source.getTags()) { + tagged.add(new XmlAdaptedTag(tag)); + } + } + + /** + * Converts this jaxb-friendly adapted task object into the model's Task object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted Task + */ + public FloatingTask toModelType() throws IllegalValueException { + final List taskTags = new ArrayList<>(); + for (XmlAdaptedTag tag : tagged) { + taskTags.add(tag.toModelType()); + } + final Name name = new Name(this.name); + final boolean complete = this.completed; + final boolean marked = this.marked; + final UniqueTagList tags = new UniqueTagList(taskTags); + return new FloatingTask(name, complete, marked, tags); + } +} diff --git a/src/main/java/seedu/address/storage/XmlAdaptedTag.java b/src/main/java/seedu/malitio/storage/XmlAdaptedTag.java similarity index 77% rename from src/main/java/seedu/address/storage/XmlAdaptedTag.java rename to src/main/java/seedu/malitio/storage/XmlAdaptedTag.java index b9723fafbc67..1bff4d740366 100644 --- a/src/main/java/seedu/address/storage/XmlAdaptedTag.java +++ b/src/main/java/seedu/malitio/storage/XmlAdaptedTag.java @@ -1,8 +1,8 @@ -package seedu.address.storage; +package seedu.malitio.storage; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.commons.util.CollectionUtil; +import seedu.malitio.model.tag.Tag; import javax.xml.bind.annotation.XmlValue; @@ -31,7 +31,7 @@ public XmlAdaptedTag(Tag source) { /** * Converts this jaxb-friendly adapted tag object into the model's Tag object. * - * @throws IllegalValueException if there were any data constraints violated in the adapted person + * @throws IllegalValueException if there were any data constraints violated in the adapted task */ public Tag toModelType() throws IllegalValueException { return new Tag(tagName); diff --git a/src/main/java/seedu/address/storage/XmlFileStorage.java b/src/main/java/seedu/malitio/storage/XmlFileStorage.java similarity index 57% rename from src/main/java/seedu/address/storage/XmlFileStorage.java rename to src/main/java/seedu/malitio/storage/XmlFileStorage.java index 27a5210cadaf..d116d276872a 100644 --- a/src/main/java/seedu/address/storage/XmlFileStorage.java +++ b/src/main/java/seedu/malitio/storage/XmlFileStorage.java @@ -1,35 +1,35 @@ -package seedu.address.storage; +package seedu.malitio.storage; -import seedu.address.commons.util.XmlUtil; -import seedu.address.commons.exceptions.DataConversionException; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.XmlUtil; import javax.xml.bind.JAXBException; import java.io.File; import java.io.FileNotFoundException; /** - * Stores addressbook data in an XML file + * Stores Malitio data in an XML file */ public class XmlFileStorage { /** - * Saves the given addressbook data to the specified file. + * Saves the given Malitio data to the specified file. */ - public static void saveDataToFile(File file, XmlSerializableAddressBook addressBook) + public static void saveDataToFile(File file, XmlSerializableMalitio malitio) throws FileNotFoundException { try { - XmlUtil.saveDataToFile(file, addressBook); + XmlUtil.saveDataToFile(file, malitio); } catch (JAXBException e) { assert false : "Unexpected exception " + e.getMessage(); } } /** - * Returns address book in the file or an empty address book + * Returns malitio in the file or an empty malitio */ - public static XmlSerializableAddressBook loadDataFromSaveFile(File file) throws DataConversionException, + public static XmlSerializableMalitio loadDataFromSaveFile(File file) throws DataConversionException, FileNotFoundException { try { - return XmlUtil.getDataFromFile(file, XmlSerializableAddressBook.class); + return XmlUtil.getDataFromFile(file, XmlSerializableMalitio.class); } catch (JAXBException e) { throw new DataConversionException(e); } diff --git a/src/main/java/seedu/malitio/storage/XmlMalitioStorage.java b/src/main/java/seedu/malitio/storage/XmlMalitioStorage.java new file mode 100644 index 000000000000..43e96589ed5c --- /dev/null +++ b/src/main/java/seedu/malitio/storage/XmlMalitioStorage.java @@ -0,0 +1,73 @@ +package seedu.malitio.storage; + +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.model.ReadOnlyMalitio; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Optional; +import java.util.logging.Logger; + +/** + * A class to access Malitio data stored as an xml file on the hard disk. + */ +public class XmlMalitioStorage implements MalitioStorage { + + private static final Logger logger = LogsCenter.getLogger(XmlMalitioStorage.class); + + private String filePath; + + public XmlMalitioStorage(String filePath){ + this.filePath = filePath; + } + + public String getMalitioFilePath(){ + return filePath; + } + + /** + * Similar to {@link #readMalitio()} + * @param filePath location of the data. Cannot be null + * @throws DataConversionException if the file is not in the correct format. + */ + public Optional readMalitio(String filePath) throws DataConversionException, FileNotFoundException { + assert filePath != null; + + File malitioFile = new File(filePath); + + if (!malitioFile.exists()) { + logger.info("malitio file " + malitioFile + " not found"); + return Optional.empty(); + } + + ReadOnlyMalitio malitioOptional = XmlFileStorage.loadDataFromSaveFile(new File(filePath)); + + return Optional.of(malitioOptional); + } + + /** + * Similar to {@link #saveMalitio(ReadOnlyMalitio)} + * @param filePath location of the data. Cannot be null + */ + public void saveMalitio(ReadOnlyMalitio malitio, String filePath) throws IOException { + assert malitio != null; + assert filePath != null; + + File file = new File(filePath); + FileUtil.createIfMissing(file); + XmlFileStorage.saveDataToFile(file, new XmlSerializableMalitio(malitio)); + } + + @Override + public Optional readMalitio() throws DataConversionException, IOException { + return readMalitio(filePath); + } + + @Override + public void saveMalitio(ReadOnlyMalitio malitio) throws IOException { + saveMalitio(malitio, filePath); + } +} diff --git a/src/main/java/seedu/malitio/storage/XmlSerializableMalitio.java b/src/main/java/seedu/malitio/storage/XmlSerializableMalitio.java new file mode 100644 index 000000000000..085a588276ae --- /dev/null +++ b/src/main/java/seedu/malitio/storage/XmlSerializableMalitio.java @@ -0,0 +1,153 @@ +package seedu.malitio.storage; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueEventList; +import seedu.malitio.model.task.UniqueFloatingTaskList; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * An Immutable Malitio that is serializable to XML format + */ +@XmlRootElement(name = "malitio") +public class XmlSerializableMalitio implements ReadOnlyMalitio { + + @XmlElement + private List floatingTasks; + @XmlElement + private List deadlines; + @XmlElement + private List events; + @XmlElement + private List tags; + + { + floatingTasks = new ArrayList<>(); + deadlines = new ArrayList<>(); + events = new ArrayList<>(); + tags = new ArrayList<>(); + } + + /** + * Empty constructor required for marshalling + */ + public XmlSerializableMalitio() {} + + /** + * Conversion + */ + public XmlSerializableMalitio(ReadOnlyMalitio src) { + floatingTasks.addAll(src.getFloatingTaskList().stream().map(XmlAdaptedFloatingTask::new).collect(Collectors.toList())); + deadlines.addAll(src.getDeadlineList().stream().map(XmlAdaptedDeadline::new).collect(Collectors.toList())); + events.addAll(src.getEventList().stream().map(XmlAdaptedEvent::new).collect(Collectors.toList())); + tags = src.getTagList(); + } + + @Override + public UniqueTagList getUniqueTagList() { + try { + return new UniqueTagList(tags); + } catch (UniqueTagList.DuplicateTagException e) { + //TODO: better error handling + e.printStackTrace(); + return null; + } + } + + @Override + public UniqueFloatingTaskList getUniqueFloatingTaskList() { + UniqueFloatingTaskList lists = new UniqueFloatingTaskList(); + for (XmlAdaptedFloatingTask p : floatingTasks) { + try { + lists.add(p.toModelType()); + } catch (IllegalValueException e) { + //TODO: better error handling + } + } + return lists; + } + + @Override + public UniqueDeadlineList getUniqueDeadlineList() { + UniqueDeadlineList lists = new UniqueDeadlineList(); + for (XmlAdaptedDeadline p : deadlines) { + try { + lists.add(p.toModelType()); + } catch (IllegalValueException e) { + //TODO: better error handling + } + } + return lists; + } + + @Override + public UniqueEventList getUniqueEventList() { + UniqueEventList lists = new UniqueEventList(); + for (XmlAdaptedEvent p : events) { + try { + lists.add(p.toModelType()); + } catch (IllegalValueException e) { + //TODO: better error handling + } + } + return lists; + } + + @Override + public List getFloatingTaskList() { + return floatingTasks.stream().map(p -> { + try { + return p.toModelType(); + } catch (IllegalValueException e) { + e.printStackTrace(); + //TODO: better error handling + return null; + } + }).collect(Collectors.toCollection(ArrayList::new)); + } + + @Override + public List getDeadlineList() { + return deadlines.stream().map(p -> { + try { + return p.toModelType(); + } catch (IllegalValueException e) { + e.printStackTrace(); + //TODO: better error handling + return null; + } + }).collect(Collectors.toCollection(ArrayList::new)); + } + + @Override + public List getEventList() { + return events.stream().map(p -> { + try { + return p.toModelType(); + } catch (IllegalValueException e) { + e.printStackTrace(); + //TODO: better error handling + return null; + } + }).collect(Collectors.toCollection(ArrayList::new)); + } + + @Override + public List getTagList() { + return Collections.unmodifiableList(tags); + } + + +} diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/malitio/ui/CommandBox.java similarity index 89% rename from src/main/java/seedu/address/ui/CommandBox.java rename to src/main/java/seedu/malitio/ui/CommandBox.java index 2e1409a3016c..2fd928b676e5 100644 --- a/src/main/java/seedu/address/ui/CommandBox.java +++ b/src/main/java/seedu/malitio/ui/CommandBox.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.malitio.ui; import com.google.common.eventbus.Subscribe; import javafx.fxml.FXML; @@ -7,11 +7,11 @@ import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import seedu.address.commons.events.ui.IncorrectCommandAttemptedEvent; -import seedu.address.logic.Logic; -import seedu.address.logic.commands.*; -import seedu.address.commons.util.FxViewUtil; -import seedu.address.commons.core.LogsCenter; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.ui.IncorrectCommandAttemptedEvent; +import seedu.malitio.commons.util.FxViewUtil; +import seedu.malitio.logic.Logic; +import seedu.malitio.logic.commands.*; import java.util.logging.Logger; @@ -65,6 +65,13 @@ public String getFxmlPath() { public void setPlaceholder(AnchorPane pane) { this.placeHolderPane = pane; } + + /** + * Clears the command box + */ + public void clearCommandBox() { + commandTextField.clear(); + } @FXML @@ -110,5 +117,5 @@ private void restoreCommandText() { private void setStyleToIndicateIncorrectCommand() { commandTextField.getStyleClass().add("error"); } - + } diff --git a/src/main/java/seedu/malitio/ui/DeadlineCard.java b/src/main/java/seedu/malitio/ui/DeadlineCard.java new file mode 100644 index 000000000000..3233482e594f --- /dev/null +++ b/src/main/java/seedu/malitio/ui/DeadlineCard.java @@ -0,0 +1,85 @@ +package seedu.malitio.ui; + +import java.util.Date; + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import seedu.malitio.model.task.ReadOnlyDeadline; + + +public class DeadlineCard extends UiPart{ + + + private static final String FXML = "DeadlineListCard.fxml"; + + @FXML + private HBox cardPane2; + @FXML + private Label name; + @FXML + private Label id; + @FXML + private Label due; + + @FXML + private Label tags; + + private ReadOnlyDeadline deadline; + private int displayedIndex; + + public DeadlineCard(){ + + } + + public static DeadlineCard load(ReadOnlyDeadline deadline, int displayedIndex){ + DeadlineCard card = new DeadlineCard(); + card.deadline = deadline; + card.displayedIndex = displayedIndex; + return UiPartLoader.loadUiPart(card); + } + + @FXML + public void initialize() { + if (deadline.getCompleted()){ + name.setText(deadline.getName().fullName); + id.setStyle("-fx-text-fill: gray;"); + name.setStyle("-fx-text-fill: gray;"); + due.setStyle("-fx-text-fill: gray;"); + tags.setStyle("-fx-text-fill: gray;"); + name.getStylesheets().addAll(getClass().getResource("/view/strikethrough.css").toExternalForm()); + } else { + name.setText(deadline.getName().fullName); + } + + if (deadline.isMarked()) { + cardPane2.setStyle("-fx-background-color: yellow;"); + } else { + cardPane2.setStyle("-fx-background-color: white;"); + } + + if (deadline.getDue().compareTo(new Date())<0 && !deadline.getCompleted()){ + name.setText(deadline.getName().fullName); + cardPane2.setStyle("-fx-background-color: red;"); + } + + id.setText("D" + displayedIndex + ". "); + due.setText("Due: "+ deadline.getDue().toString()); + tags.setText(deadline.tagsString()); + } + + public HBox getLayout() { + return cardPane2; + } + + @Override + public void setNode(Node node) { + cardPane2 = (HBox)node; + } + + @Override + public String getFxmlPath() { + return FXML; + } +} diff --git a/src/main/java/seedu/malitio/ui/DeadlineListPanel.java b/src/main/java/seedu/malitio/ui/DeadlineListPanel.java new file mode 100644 index 000000000000..ac2483c348c5 --- /dev/null +++ b/src/main/java/seedu/malitio/ui/DeadlineListPanel.java @@ -0,0 +1,113 @@ +package seedu.malitio.ui; + +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.ui.DeadlinePanelSelectionChangedEvent; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; + +import java.util.logging.Logger; + +/** + * Panel containing the list of deadlines. + */ + +public class DeadlineListPanel extends UiPart { + private final Logger logger = LogsCenter.getLogger(DeadlineListPanel.class); + private static final String FXML = "DeadlineListPanel.fxml"; + private VBox panel; + private AnchorPane placeHolderPane; + + @FXML + private ListView deadlineListView; + + public DeadlineListPanel() { + super(); + } + + @Override + public void setNode(Node node) { + panel = (VBox) node; + } + + @Override + public String getFxmlPath() { + return FXML; + } + + @Override + public void setPlaceholder(AnchorPane pane) { + this.placeHolderPane = pane; + } + + public static DeadlineListPanel load(Stage primaryStage, AnchorPane deadlineListPanelPlaceholder, + ObservableList deadlineList) { + DeadlineListPanel deadlineListPanel = + UiPartLoader.loadUiPart(primaryStage, deadlineListPanelPlaceholder, new DeadlineListPanel()); + deadlineListPanel.configure(deadlineList); + return deadlineListPanel; + } + + private void configure(ObservableList deadlineList) { + setConnections(deadlineList); + addToPlaceholder(); + } + + private void setConnections(ObservableList deadlineList) { + deadlineListView.setItems(deadlineList); + deadlineListView.setCellFactory(listView -> new DeadlineListViewCell()); + setEventHandlerForSelectionChangeEvent(); + } + + private void addToPlaceholder() { + SplitPane.setResizableWithParent(placeHolderPane, false); + placeHolderPane.getChildren().add(panel); + } + + private void setEventHandlerForSelectionChangeEvent() { + deadlineListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + logger.fine("Selection in task list panel changed to : '" + newValue + "'"); + raise(new DeadlinePanelSelectionChangedEvent(newValue)); + } + }); + } + + public void scrollTo(int index) { + Platform.runLater(() -> { + deadlineListView.scrollTo(index); + }); + } + + public ListView getDeadlineListView() { + return deadlineListView; + } + + class DeadlineListViewCell extends ListCell { + + public DeadlineListViewCell() { + } + + @Override + protected void updateItem(ReadOnlyDeadline deadline, boolean empty) { + super.updateItem(deadline, empty); + + if (empty || deadline == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(DeadlineCard.load(deadline, getIndex() + 1).getLayout()); + } + } + } + +} diff --git a/src/main/java/seedu/malitio/ui/EventCard.java b/src/main/java/seedu/malitio/ui/EventCard.java new file mode 100644 index 000000000000..942d56c255a6 --- /dev/null +++ b/src/main/java/seedu/malitio/ui/EventCard.java @@ -0,0 +1,79 @@ +package seedu.malitio.ui; + +import java.util.Date; + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import seedu.malitio.model.task.ReadOnlyEvent; + + +public class EventCard extends UiPart{ + + private static final String FXML = "EventListCard.fxml"; + + @FXML + private HBox cardPane3; + @FXML + private Label name; + @FXML + private Label id; + @FXML + private Label start; + @FXML + private Label end; + @FXML + private Label tags; + + private ReadOnlyEvent event; + private int displayedIndex; + + public EventCard(){ + + } + + public static EventCard load(ReadOnlyEvent event, int displayedIndex){ + EventCard card = new EventCard(); + card.event = event; + card.displayedIndex = displayedIndex; + return UiPartLoader.loadUiPart(card); + } + + @FXML + public void initialize() { + name.setText(event.getName().fullName); + id.setText("E" + displayedIndex + ". "); + start.setText("Start: " + event.getStart().toString()); + end.setText("End: " + event.getEnd().toString()); + tags.setText(event.tagsString()); + + if (event.getEnd().compareTo(new Date())<0) { + name.setStyle("-fx-text-fill: gray;"); + id.setStyle("-fx-text-fill: gray;"); + start.setStyle("-fx-text-fill: gray;"); + end.setStyle("-fx-text-fill: gray;"); + tags.setStyle("-fx-text-fill: gray;"); + } + + if (event.isMarked()) { + cardPane3.setStyle("-fx-background-color: yellow;"); + } else { + cardPane3.setStyle("-fx-background-color: white;"); + } + } + + public HBox getLayout() { + return cardPane3; + } + + @Override + public void setNode(Node node) { + cardPane3 = (HBox)node; + } + + @Override + public String getFxmlPath() { + return FXML; + } +} diff --git a/src/main/java/seedu/malitio/ui/EventListPanel.java b/src/main/java/seedu/malitio/ui/EventListPanel.java new file mode 100644 index 000000000000..cb76723f217d --- /dev/null +++ b/src/main/java/seedu/malitio/ui/EventListPanel.java @@ -0,0 +1,114 @@ +package seedu.malitio.ui; + +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.ui.EventPanelSelectionChangedEvent; +import seedu.malitio.commons.events.ui.TaskPanelSelectionChangedEvent; +import seedu.malitio.model.task.ReadOnlyEvent; + +import java.util.logging.Logger; + +/** + * Panel containing the list of deadlines. + */ + + +public class EventListPanel extends UiPart { + private final Logger logger = LogsCenter.getLogger(EventListPanel.class); + private static final String FXML = "EventListPanel.fxml"; + private VBox panel; + private AnchorPane placeHolderPane; + + @FXML + private ListView eventListView; + + public EventListPanel() { + super(); + } + + @Override + public void setNode(Node node) { + panel = (VBox) node; + } + + @Override + public String getFxmlPath() { + return FXML; + } + + @Override + public void setPlaceholder(AnchorPane pane) { + this.placeHolderPane = pane; + } + + public static EventListPanel load(Stage primaryStage, AnchorPane eventListPanelPlaceholder, + ObservableList eventList) { + EventListPanel eventListPanel = + UiPartLoader.loadUiPart(primaryStage, eventListPanelPlaceholder, new EventListPanel()); + eventListPanel.configure(eventList); + return eventListPanel; + } + + private void configure(ObservableList eventList) { + setConnections(eventList); + addToPlaceholder(); + } + + private void setConnections(ObservableList eventList) { + eventListView.setItems(eventList); + eventListView.setCellFactory(listView -> new EventListViewCell()); + setEventHandlerForSelectionChangeEvent(); + } + + private void addToPlaceholder() { + SplitPane.setResizableWithParent(placeHolderPane, false); + placeHolderPane.getChildren().add(panel); + } + + private void setEventHandlerForSelectionChangeEvent() { + eventListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + logger.fine("Selection in task list panel changed to : '" + newValue + "'"); + raise(new EventPanelSelectionChangedEvent(newValue)); + } + }); + } + + public void scrollTo(int index) { + Platform.runLater(() -> { + eventListView.scrollTo(index); + }); + } + + public ListView getEventListView() { + return eventListView; + } + + class EventListViewCell extends ListCell { + + public EventListViewCell() { + } + + @Override + protected void updateItem(ReadOnlyEvent event, boolean empty) { + super.updateItem(event, empty); + + if (empty || event == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(EventCard.load(event, getIndex() + 1).getLayout()); + } + } + } + +} diff --git a/src/main/java/seedu/malitio/ui/FloatingTaskCard.java b/src/main/java/seedu/malitio/ui/FloatingTaskCard.java new file mode 100644 index 000000000000..bd934185831b --- /dev/null +++ b/src/main/java/seedu/malitio/ui/FloatingTaskCard.java @@ -0,0 +1,71 @@ +package seedu.malitio.ui; + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +public class FloatingTaskCard extends UiPart{ + + private static final String FXML = "TaskListCard.fxml"; + + @FXML + private HBox cardPane; + @FXML + private Label name; + @FXML + private Label id; + @FXML + private Label tags; + + private ReadOnlyFloatingTask task; + private int displayedIndex; + + public FloatingTaskCard(){ + + } + + public static FloatingTaskCard load(ReadOnlyFloatingTask task, int displayedIndex){ + FloatingTaskCard card = new FloatingTaskCard(); + card.task = task; + card.displayedIndex = displayedIndex; + return UiPartLoader.loadUiPart(card); + } + + @FXML + public void initialize() { + if (task.getCompleted()){ + name.setText(task.getName().fullName); + name.setStyle("-fx-text-fill: gray;"); + id.setStyle("-fx-text-fill: gray;"); + tags.setStyle("-fx-text-fill: gray;"); + name.getStylesheets().addAll(getClass().getResource("/view/strikethrough.css").toExternalForm()); + } else { + name.setText(task.getName().fullName); + } + + if (task.isMarked()) { + cardPane.setStyle("-fx-background-color: yellow;"); + } else { + cardPane.setStyle("-fx-background-color: white;"); + } + + id.setText("F" + displayedIndex + ". "); + tags.setText(task.tagsString()); + } + + public HBox getLayout() { + return cardPane; + } + + @Override + public void setNode(Node node) { + cardPane = (HBox)node; + } + + @Override + public String getFxmlPath() { + return FXML; + } +} diff --git a/src/main/java/seedu/malitio/ui/FloatingTaskListPanel.java b/src/main/java/seedu/malitio/ui/FloatingTaskListPanel.java new file mode 100644 index 000000000000..15385fe20f56 --- /dev/null +++ b/src/main/java/seedu/malitio/ui/FloatingTaskListPanel.java @@ -0,0 +1,111 @@ +package seedu.malitio.ui; + +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.ui.TaskPanelSelectionChangedEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +import java.util.logging.Logger; + +/** + * Panel containing the list of tasks. + */ + +public class FloatingTaskListPanel extends UiPart { + private final Logger logger = LogsCenter.getLogger(FloatingTaskListPanel.class); + private static final String FXML = "TaskListPanel.fxml"; + private VBox panel; + private AnchorPane placeHolderPane; + + @FXML + private ListView taskListView; + + public FloatingTaskListPanel() { + super(); + } + + @Override + public void setNode(Node node) { + panel = (VBox) node; + } + + @Override + public String getFxmlPath() { + return FXML; + } + + @Override + public void setPlaceholder(AnchorPane pane) { + this.placeHolderPane = pane; + } + + public static FloatingTaskListPanel load(Stage primaryStage, AnchorPane taskListPanelPlaceholder, + ObservableList taskList) { + FloatingTaskListPanel taskListPanel = + UiPartLoader.loadUiPart(primaryStage, taskListPanelPlaceholder, new FloatingTaskListPanel()); + taskListPanel.configure(taskList); + return taskListPanel; + } + + private void configure(ObservableList taskList) { + setConnections(taskList); + addToPlaceholder(); + } + + private void setConnections(ObservableList taskList) { + taskListView.setItems(taskList); + taskListView.setCellFactory(listView -> new TaskListViewCell()); + setEventHandlerForSelectionChangeEvent(); + } + + private void addToPlaceholder() { + SplitPane.setResizableWithParent(placeHolderPane, false); + placeHolderPane.getChildren().add(panel); + } + + private void setEventHandlerForSelectionChangeEvent() { + taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + logger.fine("Selection in task list panel changed to : '" + newValue + "'"); + raise(new TaskPanelSelectionChangedEvent(newValue)); + } + }); + } + + public void scrollTo(int index) { + Platform.runLater(() -> { + taskListView.scrollTo(index); + }); + } + + public ListView getTaskListView() { + return taskListView; + } + + class TaskListViewCell extends ListCell { + + public TaskListViewCell() { + } + + @Override + protected void updateItem(ReadOnlyFloatingTask task, boolean empty) { + super.updateItem(task, empty); + + if (empty || task == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(FloatingTaskCard.load(task, getIndex() + 1).getLayout()); + } + } + } +} diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/malitio/ui/HelpWindow.java similarity index 90% rename from src/main/java/seedu/address/ui/HelpWindow.java rename to src/main/java/seedu/malitio/ui/HelpWindow.java index 45b765ab6a0c..6630ed8bae17 100644 --- a/src/main/java/seedu/address/ui/HelpWindow.java +++ b/src/main/java/seedu/malitio/ui/HelpWindow.java @@ -1,12 +1,12 @@ -package seedu.address.ui; +package seedu.malitio.ui; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.scene.web.WebView; import javafx.stage.Stage; -import seedu.address.commons.util.FxViewUtil; -import seedu.address.commons.core.LogsCenter; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.util.FxViewUtil; import java.util.logging.Logger; @@ -20,7 +20,7 @@ public class HelpWindow extends UiPart { private static final String FXML = "HelpWindow.fxml"; private static final String TITLE = "Help"; private static final String USERGUIDE_URL = - "https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md"; + "https://github.com/CS2103AUG2016-T13-C3/main/blob/master/docs/UserGuide.md"; private AnchorPane mainPane; diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/malitio/ui/MainWindow.java similarity index 60% rename from src/main/java/seedu/address/ui/MainWindow.java rename to src/main/java/seedu/malitio/ui/MainWindow.java index 2c76aced3b04..ed4e4ed04947 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/malitio/ui/MainWindow.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.malitio.ui; import javafx.fxml.FXML; import javafx.scene.Node; @@ -8,12 +8,14 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.events.ui.ExitAppRequestEvent; -import seedu.address.logic.Logic; -import seedu.address.model.UserPrefs; -import seedu.address.model.person.ReadOnlyPerson; +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.core.GuiSettings; +import seedu.malitio.commons.events.ui.ExitAppRequestEvent; +import seedu.malitio.logic.Logic; +import seedu.malitio.model.UserPrefs; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; /** * The Main Window. Provides the basic application layout containing @@ -21,16 +23,17 @@ */ public class MainWindow extends UiPart { - private static final String ICON = "/images/address_book_32.png"; + private static final String ICON = "/images/malitio.png"; private static final String FXML = "MainWindow.fxml"; public static final int MIN_HEIGHT = 600; - public static final int MIN_WIDTH = 450; + public static final int MIN_WIDTH = 1100; private Logic logic; - + // Independent Ui parts residing in this Ui container - private BrowserPanel browserPanel; - private PersonListPanel personListPanel; + private FloatingTaskListPanel taskListPanel; + private DeadlineListPanel deadlineListPanel; + private EventListPanel eventListPanel; private ResultDisplay resultDisplay; private StatusBarFooter statusBarFooter; private CommandBox commandBox; @@ -41,19 +44,25 @@ public class MainWindow extends UiPart { private VBox rootLayout; private Scene scene; - private String addressBookName; - - @FXML - private AnchorPane browserPlaceholder; + private String malitioName; @FXML private AnchorPane commandBoxPlaceholder; @FXML private MenuItem helpMenuItem; + + @FXML + private MenuItem clearCommandBoxMenuItem; @FXML - private AnchorPane personListPanelPlaceholder; + private AnchorPane taskListPanelPlaceholder; + + @FXML + private AnchorPane deadlineListPanelPlaceholder; + + @FXML + private AnchorPane eventListPanelPlaceholder; @FXML private AnchorPane resultDisplayPlaceholder; @@ -61,6 +70,8 @@ public class MainWindow extends UiPart { @FXML private AnchorPane statusbarPlaceholder; + @FXML + private AnchorPane panelTitle; public MainWindow() { super(); @@ -79,16 +90,16 @@ public String getFxmlPath() { public static MainWindow load(Stage primaryStage, Config config, UserPrefs prefs, Logic logic) { MainWindow mainWindow = UiPartLoader.loadUiPart(primaryStage, new MainWindow()); - mainWindow.configure(config.getAppTitle(), config.getAddressBookName(), config, prefs, logic); + mainWindow.configure(config.getAppTitle(), config.getMalitioName(), config, prefs, logic); return mainWindow; } - private void configure(String appTitle, String addressBookName, Config config, UserPrefs prefs, + private void configure(String appTitle, String malitioName, Config config, UserPrefs prefs, Logic logic) { //Set dependencies this.logic = logic; - this.addressBookName = addressBookName; + this.malitioName = malitioName; this.config = config; this.userPrefs = prefs; @@ -105,13 +116,15 @@ private void configure(String appTitle, String addressBookName, Config config, U private void setAccelerators() { helpMenuItem.setAccelerator(KeyCombination.valueOf("F1")); + clearCommandBoxMenuItem.setAccelerator(KeyCombination.valueOf("ESC")); } void fillInnerParts() { - browserPanel = BrowserPanel.load(browserPlaceholder); - personListPanel = PersonListPanel.load(primaryStage, getPersonListPlaceholder(), logic.getFilteredPersonList()); + taskListPanel = FloatingTaskListPanel.load(primaryStage, getTaskListPanelPlaceholder(), logic.getFilteredFloatingTaskList()); + deadlineListPanel = DeadlineListPanel.load(primaryStage, getDeadlineListPanelPlaceholder(), logic.getFilteredDeadlineList()); + eventListPanel = EventListPanel.load(primaryStage, getEventListPanelPlaceholder(), logic.getFilteredEventList()); resultDisplay = ResultDisplay.load(primaryStage, getResultDisplayPlaceholder()); - statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getAddressBookFilePath()); + statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getMalitioFilePath()); commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic); } @@ -127,8 +140,16 @@ private AnchorPane getResultDisplayPlaceholder() { return resultDisplayPlaceholder; } - public AnchorPane getPersonListPlaceholder() { - return personListPanelPlaceholder; + public AnchorPane getTaskListPanelPlaceholder() { + return taskListPanelPlaceholder; + } + + public AnchorPane getDeadlineListPanelPlaceholder() { + return deadlineListPanelPlaceholder; + } + + private AnchorPane getEventListPanelPlaceholder() { + return eventListPanelPlaceholder; } public void hide() { @@ -181,16 +202,34 @@ public void show() { private void handleExit() { raise(new ExitAppRequestEvent()); } - - public PersonListPanel getPersonListPanel() { - return this.personListPanel; + + @FXML + private void clearCommandBox() { + commandBox.clearCommandBox(); } - public void loadPersonPage(ReadOnlyPerson person) { - browserPanel.loadPersonPage(person); + public FloatingTaskListPanel getTaskListPanel() { + return this.taskListPanel; } - - public void releaseResources() { - browserPanel.freeResources(); + + public DeadlineListPanel getDeadlineListPanel() { + return this.deadlineListPanel; + } + + public EventListPanel getEventListPanel() { + return this.eventListPanel; } + + public void loadTaskDetail(ReadOnlyFloatingTask task) { + resultDisplay.postMessage(task.toString()); + } + + public void loadTaskDetail(ReadOnlyDeadline deadline) { + resultDisplay.postMessage(deadline.toString()); + } + + public void loadTaskDetail(ReadOnlyEvent event) { + resultDisplay.postMessage(event.toString()); + } + } diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/seedu/malitio/ui/ResultDisplay.java similarity index 96% rename from src/main/java/seedu/address/ui/ResultDisplay.java rename to src/main/java/seedu/malitio/ui/ResultDisplay.java index 37284ee6c696..31c66737e942 100644 --- a/src/main/java/seedu/address/ui/ResultDisplay.java +++ b/src/main/java/seedu/malitio/ui/ResultDisplay.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.malitio.ui; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -6,7 +6,7 @@ import javafx.scene.control.TextArea; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import seedu.address.commons.util.FxViewUtil; +import seedu.malitio.commons.util.FxViewUtil; /** * A ui for the status bar that is displayed at the header of the application. diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/seedu/malitio/ui/StatusBarFooter.java similarity index 81% rename from src/main/java/seedu/address/ui/StatusBarFooter.java rename to src/main/java/seedu/malitio/ui/StatusBarFooter.java index f74f66be6fc9..813c19a307d1 100644 --- a/src/main/java/seedu/address/ui/StatusBarFooter.java +++ b/src/main/java/seedu/malitio/ui/StatusBarFooter.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.malitio.ui; import com.google.common.eventbus.Subscribe; import javafx.fxml.FXML; @@ -7,9 +7,11 @@ import javafx.scene.layout.GridPane; import javafx.stage.Stage; import org.controlsfx.control.StatusBar; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.util.FxViewUtil; + +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.model.MalitioChangedEvent; +import seedu.malitio.commons.events.storage.DataStorageFileChangedEvent; +import seedu.malitio.commons.util.FxViewUtil; import java.util.Date; import java.util.logging.Logger; @@ -45,7 +47,7 @@ public void configure(String saveLocation) { addSyncStatus(); setSyncStatus("Not updated yet in this session"); addSaveLocation(); - setSaveLocation("./" + saveLocation); + setSaveLocation(saveLocation); registerAsAnEventHandler(this); } @@ -55,7 +57,7 @@ private void addMainPane() { } private void setSaveLocation(String location) { - this.saveLocationStatus.setText(location); + this.saveLocationStatus.setText("Data file is saved at " + location); } private void addSaveLocation() { @@ -90,9 +92,15 @@ public String getFxmlPath() { } @Subscribe - public void handleAddressBookChangedEvent(AddressBookChangedEvent abce) { + public void handleMalitioChangedEvent(MalitioChangedEvent abce) { String lastUpdated = (new Date()).toString(); logger.info(LogsCenter.getEventHandlingLogMessage(abce, "Setting last updated status to " + lastUpdated)); setSyncStatus("Last Updated: " + lastUpdated); } + + //@@author a0126633j + @Subscribe + public void handleDataStorageFileChangedEvent(DataStorageFileChangedEvent event) { + setSaveLocation(event.dataFilePath); + } } diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/seedu/malitio/ui/Ui.java similarity index 88% rename from src/main/java/seedu/address/ui/Ui.java rename to src/main/java/seedu/malitio/ui/Ui.java index e6a67fe8c027..0f4284c07f6d 100644 --- a/src/main/java/seedu/address/ui/Ui.java +++ b/src/main/java/seedu/malitio/ui/Ui.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.malitio.ui; import javafx.stage.Stage; diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/malitio/ui/UiManager.java similarity index 59% rename from src/main/java/seedu/address/ui/UiManager.java rename to src/main/java/seedu/malitio/ui/UiManager.java index 4a4dba3a2f6e..4242bfc9f6d2 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/seedu/malitio/ui/UiManager.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.malitio.ui; import com.google.common.eventbus.Subscribe; import javafx.application.Platform; @@ -6,17 +6,19 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.image.Image; import javafx.stage.Stage; -import seedu.address.MainApp; -import seedu.address.commons.core.ComponentManager; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.commons.events.ui.JumpToListRequestEvent; -import seedu.address.commons.events.ui.PersonPanelSelectionChangedEvent; -import seedu.address.commons.events.ui.ShowHelpRequestEvent; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; -import seedu.address.model.UserPrefs; +import seedu.malitio.MainApp; +import seedu.malitio.commons.core.ComponentManager; +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.core.LogsCenter; +import seedu.malitio.commons.events.storage.DataSavingExceptionEvent; +import seedu.malitio.commons.events.ui.TaskPanelSelectionChangedEvent; +import seedu.malitio.commons.events.ui.DeadlinePanelSelectionChangedEvent; +import seedu.malitio.commons.events.ui.EventPanelSelectionChangedEvent; +import seedu.malitio.commons.events.ui.ShowHelpRequestEvent; +import seedu.malitio.commons.events.ui.JumpToListRequestEvent; +import seedu.malitio.commons.util.StringUtil; +import seedu.malitio.logic.Logic; +import seedu.malitio.model.UserPrefs; import java.util.logging.Logger; @@ -25,7 +27,7 @@ */ public class UiManager extends ComponentManager implements Ui { private static final Logger logger = LogsCenter.getLogger(UiManager.class); - private static final String ICON_APPLICATION = "/images/address_book_32.png"; + private static final String ICON_APPLICATION = "/images/malitio.png"; private Logic logic; private Config config; @@ -62,7 +64,6 @@ public void start(Stage primaryStage) { public void stop() { prefs.updateLastUsedGuiSetting(mainWindow.getCurrentGuiSetting()); mainWindow.hide(); - mainWindow.releaseResources(); } private void showFileOperationAlertAndWait(String description, String details, Throwable cause) { @@ -111,16 +112,41 @@ private void handleShowHelpEvent(ShowHelpRequestEvent event) { mainWindow.handleHelp(); } + //@@author A0129595N @Subscribe - private void handleJumpToListRequestEvent(JumpToListRequestEvent event) { + private void handleTaskPanelSelectionChangedEvent(TaskPanelSelectionChangedEvent event){ logger.info(LogsCenter.getEventHandlingLogMessage(event)); - mainWindow.getPersonListPanel().scrollTo(event.targetIndex); + mainWindow.loadTaskDetail(event.getNewFloatingTaskSelection()); + mainWindow.getEventListPanel().getEventListView().getSelectionModel().clearSelection(); + mainWindow.getDeadlineListPanel().getDeadlineListView().getSelectionModel().clearSelection(); } - + + @Subscribe + private void handleDeadlinePanelSelectionChangedEvent(DeadlinePanelSelectionChangedEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + mainWindow.loadTaskDetail(event.getNewDeadlineSelection()); + mainWindow.getEventListPanel().getEventListView().getSelectionModel().clearSelection(); + mainWindow.getTaskListPanel().getTaskListView().getSelectionModel().clearSelection(); + } + @Subscribe - private void handlePersonPanelSelectionChangedEvent(PersonPanelSelectionChangedEvent event){ + private void handleEventPanelSelectionChangedEvent(EventPanelSelectionChangedEvent event) { logger.info(LogsCenter.getEventHandlingLogMessage(event)); - mainWindow.loadPersonPage(event.getNewSelection()); + mainWindow.loadTaskDetail(event.getNewEventSelection()); + mainWindow.getTaskListPanel().getTaskListView().getSelectionModel().clearSelection(); + mainWindow.getDeadlineListPanel().getDeadlineListView().getSelectionModel().clearSelection(); } + @Subscribe + private void handleJumpToTaskListRequestEvent(JumpToListRequestEvent event) { + String taskType = event.typeOfTask; + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + if (taskType.equals("floating task")) { + mainWindow.getTaskListPanel().scrollTo(event.targetIndex); + } else if (taskType.equals("deadline")) { + mainWindow.getDeadlineListPanel().scrollTo(event.targetIndex); + } else { + mainWindow.getEventListPanel().scrollTo(event.targetIndex); + } + } } diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/seedu/malitio/ui/UiPart.java similarity index 94% rename from src/main/java/seedu/address/ui/UiPart.java rename to src/main/java/seedu/malitio/ui/UiPart.java index 0a4ceb33e9b7..2dd7f1102a0f 100644 --- a/src/main/java/seedu/address/ui/UiPart.java +++ b/src/main/java/seedu/malitio/ui/UiPart.java @@ -1,13 +1,13 @@ -package seedu.address.ui; +package seedu.malitio.ui; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; import javafx.stage.Stage; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.BaseEvent; -import seedu.address.commons.util.AppUtil; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.events.BaseEvent; +import seedu.malitio.commons.util.AppUtil; /** * Base class for UI parts. diff --git a/src/main/java/seedu/address/ui/UiPartLoader.java b/src/main/java/seedu/malitio/ui/UiPartLoader.java similarity index 97% rename from src/main/java/seedu/address/ui/UiPartLoader.java rename to src/main/java/seedu/malitio/ui/UiPartLoader.java index f880685a5b15..d3593644313e 100644 --- a/src/main/java/seedu/address/ui/UiPartLoader.java +++ b/src/main/java/seedu/malitio/ui/UiPartLoader.java @@ -1,10 +1,10 @@ -package seedu.address.ui; +package seedu.malitio.ui; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import seedu.address.MainApp; +import seedu.malitio.MainApp; /** * A utility class to load UiParts from FXML files. diff --git a/src/main/resources/images/malitio.png b/src/main/resources/images/malitio.png new file mode 100644 index 000000000000..7ef39422f730 Binary files /dev/null and b/src/main/resources/images/malitio.png differ diff --git a/src/main/resources/view/CommandBox.fxml b/src/main/resources/view/CommandBox.fxml index 575de420b994..20dccb243883 100644 --- a/src/main/resources/view/CommandBox.fxml +++ b/src/main/resources/view/CommandBox.fxml @@ -2,8 +2,10 @@ - - + + diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 8043b344253a..bfc80629d10b 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -278,11 +278,31 @@ -fx-border-width: 1 1 1 1; } +#cardPane2 { + -fx-background-color: transparent; + -fx-border-color: #d6d6d6; + -fx-border-width: 1 1 1 1; +} + +#cardPane3 { + -fx-background-color: transparent; + -fx-border-color: #d6d6d6; + -fx-border-width: 1 1 1 1; +} + #commandTypeLabel { -fx-font-size: 11px; -fx-text-fill: #F70D1A; } -#filterField, #personListPanel, #personWebpage { +#filterField, #taskListPanel, #taskWebpage { -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0); +} + +#floatingTaskTitle, #deadlineTitle, #eventTitle { + -fx-font-size: 13pt; + -fx-font-family: "Segoe UI Semibold"; + -fx-text-fill: white; + -fx-font-weight: bold; + -fx-opacity: 0.9; } \ No newline at end of file diff --git a/src/main/resources/view/DeadlineListCard.fxml b/src/main/resources/view/DeadlineListCard.fxml new file mode 100644 index 000000000000..578fe14c484c --- /dev/null +++ b/src/main/resources/view/DeadlineListCard.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/DeadlineListPanel.fxml b/src/main/resources/view/DeadlineListPanel.fxml new file mode 100644 index 000000000000..899759ea7088 --- /dev/null +++ b/src/main/resources/view/DeadlineListPanel.fxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml b/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml deleted file mode 100644 index bc761118235a..000000000000 --- a/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - diff --git a/src/main/resources/view/EventListCard.fxml b/src/main/resources/view/EventListCard.fxml new file mode 100644 index 000000000000..ed88b204f141 --- /dev/null +++ b/src/main/resources/view/EventListCard.fxml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/EventListPanel.fxml b/src/main/resources/view/EventListPanel.fxml new file mode 100644 index 000000000000..d655780ac5e6 --- /dev/null +++ b/src/main/resources/view/EventListPanel.fxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml index c4cbd84cac28..2e894f30aa07 100644 --- a/src/main/resources/view/HelpWindow.fxml +++ b/src/main/resources/view/HelpWindow.fxml @@ -1,8 +1,11 @@ - - + + - + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 2f9235c621d8..2af8c8c1f91b 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -1,56 +1,92 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml deleted file mode 100644 index 13d4b149651b..000000000000 --- a/src/main/resources/view/PersonListCard.fxml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PersonListPanel.fxml deleted file mode 100644 index 000c4c999b65..000000000000 --- a/src/main/resources/view/PersonListPanel.fxml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml index cc650d739e22..60f6c8e54bfe 100644 --- a/src/main/resources/view/ResultDisplay.fxml +++ b/src/main/resources/view/ResultDisplay.fxml @@ -2,10 +2,10 @@ - - - - - + + + + + diff --git a/src/main/resources/view/StatusBarFooter.fxml b/src/main/resources/view/StatusBarFooter.fxml index 2656558b6eb7..651e469d51a2 100644 --- a/src/main/resources/view/StatusBarFooter.fxml +++ b/src/main/resources/view/StatusBarFooter.fxml @@ -1,13 +1,19 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml new file mode 100644 index 000000000000..5e60e8a7cf40 --- /dev/null +++ b/src/main/resources/view/TaskListCard.fxml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/TaskListPanel.fxml b/src/main/resources/view/TaskListPanel.fxml new file mode 100644 index 000000000000..d30c1ef84bba --- /dev/null +++ b/src/main/resources/view/TaskListPanel.fxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/view/strikethrough.css b/src/main/resources/view/strikethrough.css new file mode 100644 index 000000000000..89236fa1de83 --- /dev/null +++ b/src/main/resources/view/strikethrough.css @@ -0,0 +1,3 @@ +.label .text { + -fx-strikethrough: true; +} \ No newline at end of file diff --git a/src/test/data/ConfigUtilTest/ExtraValuesConfig.json b/src/test/data/ConfigUtilTest/ExtraValuesConfig.json index 578b4445204b..70640e9a1937 100644 --- a/src/test/data/ConfigUtilTest/ExtraValuesConfig.json +++ b/src/test/data/ConfigUtilTest/ExtraValuesConfig.json @@ -2,7 +2,7 @@ "appTitle" : "Typical App Title", "logLevel" : "INFO", "userPrefsFilePath" : "C:\\preferences.json", - "addressBookFilePath" : "addressbook.xml", - "addressBookName" : "TypicalAddressBookName", + "malitioFilePath" : "malitio.xml", + "malitioName" : "TypicalmalitioName", "extra" : "extra value" } \ No newline at end of file diff --git a/src/test/data/ConfigUtilTest/TypicalConfig.json b/src/test/data/ConfigUtilTest/TypicalConfig.json index 195b2bf33033..452bce52236c 100644 --- a/src/test/data/ConfigUtilTest/TypicalConfig.json +++ b/src/test/data/ConfigUtilTest/TypicalConfig.json @@ -2,6 +2,6 @@ "appTitle" : "Typical App Title", "logLevel" : "INFO", "userPrefsFilePath" : "C:\\preferences.json", - "addressBookFilePath" : "addressbook.xml", - "addressBookName" : "TypicalAddressBookName" + "malitioFilePath" : "malitio.xml", + "malitioName" : "TypicalmalitioName" } \ No newline at end of file diff --git a/src/test/data/XmlAddressBookStorageTest/NotXmlFormatAddressBook.xml b/src/test/data/XmlMalitioStorageTest/NotXmlFormatMalitio.xml similarity index 93% rename from src/test/data/XmlAddressBookStorageTest/NotXmlFormatAddressBook.xml rename to src/test/data/XmlMalitioStorageTest/NotXmlFormatMalitio.xml index 49d5d80d27a1..f1528c3ea675 100644 --- a/src/test/data/XmlAddressBookStorageTest/NotXmlFormatAddressBook.xml +++ b/src/test/data/XmlMalitioStorageTest/NotXmlFormatMalitio.xml @@ -1 +1,2 @@ + not xml format! \ No newline at end of file diff --git a/src/test/data/XmlUtilTest/tempAddressBook.xml b/src/test/data/XmlUtilTest/tempAddressBook.xml deleted file mode 100644 index 41eeb8eb391a..000000000000 --- a/src/test/data/XmlUtilTest/tempAddressBook.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - 1 - John - Doe - - - - - - - Friends - - diff --git a/src/test/data/XmlUtilTest/tempMalitio.xml b/src/test/data/XmlUtilTest/tempMalitio.xml new file mode 100644 index 000000000000..2bd83aa648fb --- /dev/null +++ b/src/test/data/XmlUtilTest/tempMalitio.xml @@ -0,0 +1,15 @@ + + + + 1 + John + Doe + + + + + + + Friends + + diff --git a/src/test/data/XmlUtilTest/validAddressBook.xml b/src/test/data/XmlUtilTest/validAddressBook.xml deleted file mode 100644 index eafca730fb1e..000000000000 --- a/src/test/data/XmlUtilTest/validAddressBook.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - Hans Muster - 9482424 - hans@google.com -
4th street
-
- - Ruth Mueller - 87249245 - ruth@google.com -
81th street
-
- - Heinz Kurz - 95352563 - heinz@yahoo.com -
wall street
-
- - Cornelia Meier - 87652533 - cornelia@google.com -
10th street
-
- - Werner Meyer - 9482224 - werner@gmail.com -
michegan ave
-
- - Lydia Kunz - 9482427 - lydia@gmail.com -
little tokyo
-
- - Anna Best - 9482442 - anna@google.com -
4th street
-
- - Stefan Meier - 8482424 - stefan@mail.com -
little india
-
- - Martin Mueller - 8482131 - hans@google.com -
chicago ave
-
-
diff --git a/src/test/data/XmlUtilTest/validMalitio.xml b/src/test/data/XmlUtilTest/validMalitio.xml new file mode 100644 index 000000000000..87888430b5ff --- /dev/null +++ b/src/test/data/XmlUtilTest/validMalitio.xml @@ -0,0 +1,30 @@ + + + + Hans Muster + + + Ruth Mueller + + + Heinz Kurz + + + Cornelia Meier + + + Werner Meyer + + + Lydia Kunz + + + Anna Best + + + Stefan Meier + + + Martin Mueller + + diff --git a/src/test/data/tempDataForSaveCommand/malitio.xml b/src/test/data/tempDataForSaveCommand/malitio.xml new file mode 100644 index 000000000000..3ce27d59b078 --- /dev/null +++ b/src/test/data/tempDataForSaveCommand/malitio.xml @@ -0,0 +1,140 @@ + + + + Adjust meter + false + false + careful + + + Bring along notes + false + false + pen + cs2103 + + + Tell your world + false + false + + + Download Promise Song + false + false + + + Cendrillion + false + false + vocaloid + + + Cut hair + false + false + 12-Oct-2016, 20:00 (Wed) + + + Do some sit-up + false + false + 31-Oct-2016, 23:59 (Mon) + + + Buy stuff + false + false + 01-Nov-2016, 17:45 (Tue) + Pencil + + + Practice singing + false + false + 25-Dec-2016, 00:00 (Sun) + Christmas + Carols + + + Finish homework + false + false + 31-Dec-2016, 23:00 (Sat) + help + + + Eat with mom + 10-Jan-2017, 18:00 (Tue) + 10-Jan-2017, 18:55 (Tue) + yummy + + + Forgive with forget + 22-Feb-2017, 10:00 (Wed) + 23-Feb-2017, 10:00 (Thu) + peace + + + Go shopping + 30-Mar-2017, 09:00 (Thu) + 30-Mar-2017, 20:00 (Thu) + clothes + + + Hopping + 01-Nov-2017, 04:00 (Wed) + 01-Nov-2017, 06:00 (Wed) + hello + + + Christmas party + 25-Dec-2017, 00:00 (Mon) + 25-Dec-2017, 23:59 (Mon) + presents + + + New year party + 31-Dec-2017, 00:00 (Sun) + 31-Dec-2017, 23:59 (Sun) + + + careful + + + pen + + + cs2103 + + + vocaloid + + + Pencil + + + Christmas + + + Carols + + + help + + + yummy + + + peace + + + clothes + + + hello + + + presents + + diff --git a/src/test/java/guitests/AddCommandTest.java b/src/test/java/guitests/AddCommandTest.java index 3b2e1844bd0d..dff360fc8a28 100644 --- a/src/test/java/guitests/AddCommandTest.java +++ b/src/test/java/guitests/AddCommandTest.java @@ -1,53 +1,133 @@ package guitests; -import guitests.guihandles.PersonCardHandle; +import guitests.guihandles.DeadlineCardHandle; +import guitests.guihandles.EventCardHandle; +import guitests.guihandles.FloatingTaskCardHandle; import org.junit.Test; -import seedu.address.logic.commands.AddCommand; -import seedu.address.commons.core.Messages; -import seedu.address.testutil.TestPerson; -import seedu.address.testutil.TestUtil; + +import seedu.malitio.testutil.TestDeadline; +import seedu.malitio.testutil.TestEvent; +import seedu.malitio.testutil.TestFloatingTask; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.ui.DeadlineListPanel; +import seedu.malitio.ui.FloatingTaskListPanel; +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.logic.commands.AddCommand; import static org.junit.Assert.assertTrue; -public class AddCommandTest extends AddressBookGuiTest { +public class AddCommandTest extends MalitioGuiTest { @Test - public void add() { - //add one person - TestPerson[] currentList = td.getTypicalPersons(); - TestPerson personToAdd = td.hoon; - assertAddSuccess(personToAdd, currentList); - currentList = TestUtil.addPersonsToList(currentList, personToAdd); - - //add another person - personToAdd = td.ida; - assertAddSuccess(personToAdd, currentList); - currentList = TestUtil.addPersonsToList(currentList, personToAdd); - - //add duplicate person - commandBox.runCommand(td.hoon.getAddCommand()); - assertResultMessage(AddCommand.MESSAGE_DUPLICATE_PERSON); - assertTrue(personListPanel.isListMatching(currentList)); + public void addTask() { + //add one task + TestFloatingTask[] currentList = td.getTypicalFloatingTasks(); + TestFloatingTask taskToAdd = td.manualFloatingTask1; + assertAddSuccess(taskToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, taskToAdd); + + //add another task + taskToAdd = td.manualFloatingTask2; + assertAddSuccess(taskToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, taskToAdd); + + //add duplicate task + commandBox.runCommand(td.manualFloatingTask1.getAddCommand()); + assertResultMessage(AddCommand.MESSAGE_DUPLICATE_TASK); + assertTrue(floatingTaskListPanel.isListMatching(currentList)); //add to empty list commandBox.runCommand("clear"); - assertAddSuccess(td.alice); + assertAddSuccess(td.floatingTask1); //invalid command - commandBox.runCommand("adds Johnny"); + commandBox.runCommand("adds run"); assertResultMessage(Messages.MESSAGE_UNKNOWN_COMMAND); } - private void assertAddSuccess(TestPerson personToAdd, TestPerson... currentList) { - commandBox.runCommand(personToAdd.getAddCommand()); + @Test + public void addDeadline() { + + //add one deadline + TestDeadline[] currentList = td.getTypicalDeadlines(); + TestDeadline deadlineToAdd = td.manualDeadline1; + assertAddSuccess(deadlineToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, deadlineToAdd); + + //add another deadline + deadlineToAdd = td.manualDeadline2; + assertAddSuccess(deadlineToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, deadlineToAdd); + + //add duplicate deadline + commandBox.runCommand(td.deadline1.getAddCommand()); + assertResultMessage(AddCommand.MESSAGE_DUPLICATE_DEADLINE); + assertTrue(deadlineListPanel.isListMatching(currentList)); + + //add to empty list + commandBox.runCommand("clear"); + assertAddSuccess(td.deadline1); + } + + @Test + public void addEvent() throws IllegalArgumentException, IllegalValueException { + + //add one event + TestEvent[] currentList = td.getTypicalEvents(); + TestEvent eventToAdd = td.manualEvent1; + assertAddSuccess(eventToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, eventToAdd); + + //add another event + eventToAdd = td.manualEvent2; + assertAddSuccess(eventToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, eventToAdd); + + //add duplicate event + commandBox.runCommand(td.manualEvent1.getAddCommand()); + assertResultMessage(AddCommand.MESSAGE_DUPLICATE_EVENT); + assertTrue(eventListPanel.isListMatching(currentList)); + + //add to empty list + commandBox.runCommand("clear"); + assertAddSuccess(td.event1); + } + + private void assertAddSuccess(TestFloatingTask taskToAdd, TestFloatingTask... currentList) { + commandBox.runCommand(taskToAdd.getAddCommand()); + + //confirm the new card contains the right data + FloatingTaskCardHandle addedCard = floatingTaskListPanel.navigateToTask(taskToAdd.getName().fullName); + assertMatching(taskToAdd, addedCard); + + //confirm the list now contains all previous tasks plus the new task + TestFloatingTask[] expectedList = TestUtil.addTasksToList(currentList, taskToAdd); + assertTrue(floatingTaskListPanel.isListMatching(expectedList)); + } + + private void assertAddSuccess(TestDeadline deadlineToAdd, TestDeadline... currentList) { + commandBox.runCommand(deadlineToAdd.getAddCommand()); + + //confirm the new card contains the right data + DeadlineCardHandle addedCard = deadlineListPanel.navigateToTask(deadlineToAdd.getName().fullName); + assertMatching(deadlineToAdd, addedCard); + + //confirm the list now contains all previous tasks plus the new task + TestDeadline[] expectedList = TestUtil.addTasksToList(currentList, deadlineToAdd); + assertTrue(deadlineListPanel.isListMatching(expectedList)); + } + + private void assertAddSuccess(TestEvent eventToAdd, TestEvent... currentList) throws IllegalArgumentException, IllegalValueException { + commandBox.runCommand(eventToAdd.getAddCommand()); //confirm the new card contains the right data - PersonCardHandle addedCard = personListPanel.navigateToPerson(personToAdd.getName().fullName); - assertMatching(personToAdd, addedCard); + EventCardHandle addedCard = eventListPanel.navigateToTask(eventToAdd.getName().fullName); + assertMatching(eventToAdd, addedCard); - //confirm the list now contains all previous persons plus the new person - TestPerson[] expectedList = TestUtil.addPersonsToList(currentList, personToAdd); - assertTrue(personListPanel.isListMatching(expectedList)); + //confirm the list now contains all previous tasks plus the new task + TestEvent[] expectedList = TestUtil.addTasksToList(currentList, eventToAdd); + assertTrue(eventListPanel.isListMatching(expectedList)); } } diff --git a/src/test/java/guitests/ClearCommandTest.java b/src/test/java/guitests/ClearCommandTest.java index 9d52b427659c..86b0d36b742f 100644 --- a/src/test/java/guitests/ClearCommandTest.java +++ b/src/test/java/guitests/ClearCommandTest.java @@ -2,30 +2,60 @@ import org.junit.Test; +import seedu.malitio.logic.commands.ClearCommand; + import static org.junit.Assert.assertTrue; +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -public class ClearCommandTest extends AddressBookGuiTest { +public class ClearCommandTest extends MalitioGuiTest { @Test public void clear() { //verify a non-empty list can be cleared - assertTrue(personListPanel.isListMatching(td.getTypicalPersons())); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); assertClearCommandSuccess(); //verify other commands can work after a clear command - commandBox.runCommand(td.hoon.getAddCommand()); - assertTrue(personListPanel.isListMatching(td.hoon)); - commandBox.runCommand("delete 1"); - assertListSize(0); + commandBox.runCommand(td.manualFloatingTask1.getAddCommand()); + assertTrue(floatingTaskListPanel.isListMatching(td.manualFloatingTask1)); + commandBox.runCommand("delete f1"); + assertTotalListSize(0); //verify clear command works when the list is empty assertClearCommandSuccess(); } - + + //@@author a0126633j + @Test + public void clearExpired_containsExpiredTasks_success() { + commandBox.runCommand("complete d2"); + commandBox.runCommand("complete f1"); + commandBox.runCommand("complete f3"); + + commandBox.runCommand(td.manualEvent3.getAddCommand()); + commandBox.runCommand("listall"); + assertTotalListSize(17); + + commandBox.runCommand("clear expired"); //clear 4 tasks + commandBox.runCommand("listall"); + assertTotalListSize(13); + + commandBox.runCommand("clear expired"); //does not clear anything + commandBox.runCommand("listall"); + assertTotalListSize(13); + } + + @Test + public void clearExpired_invalidArgument_unsuccessful() { + commandBox.runCommand("clear something"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ClearCommand.MESSAGE_USAGE)); + } + //@@author + private void assertClearCommandSuccess() { commandBox.runCommand("clear"); - assertListSize(0); - assertResultMessage("Address book has been cleared!"); + assertTotalListSize(0); + assertResultMessage("Malitio has been cleared!"); } } diff --git a/src/test/java/guitests/CommandBoxTest.java b/src/test/java/guitests/CommandBoxTest.java index 1379198bf8b0..cb49af689edb 100644 --- a/src/test/java/guitests/CommandBoxTest.java +++ b/src/test/java/guitests/CommandBoxTest.java @@ -4,11 +4,11 @@ import static org.junit.Assert.assertEquals; -public class CommandBoxTest extends AddressBookGuiTest { +public class CommandBoxTest extends MalitioGuiTest { @Test public void commandBox_commandSucceeds_textCleared() { - commandBox.runCommand(td.benson.getAddCommand()); + commandBox.runCommand(td.floatingTask2.getAddCommand()); assertEquals(commandBox.getCommandInput(), ""); } diff --git a/src/test/java/guitests/CompleteCommandTest.java b/src/test/java/guitests/CompleteCommandTest.java new file mode 100644 index 000000000000..4599689e37c9 --- /dev/null +++ b/src/test/java/guitests/CompleteCommandTest.java @@ -0,0 +1,51 @@ +package guitests; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.logic.commands.CompleteCommand; + +import org.junit.Test; +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +//@@author A0122460W +public class CompleteCommandTest extends MalitioGuiTest { + + @Test + public void completeFloatingtask() { + + // complete floating task + commandBox.runCommand("complete f1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_TASK_SUCCESS)); + + // cannot complete a completed floating task + commandBox.runCommand("complete f1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_TASK)); + + // complete error command + commandBox.runCommand("complete"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + + commandBox.runCommand("complete asdf"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE)); + + // complete with an invalid index + commandBox.runCommand("complete f200"); + assertResultMessage(String.format(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX)); + } + + @Test + public void completeDeadline() { + + // complete deadline + commandBox.runCommand("complete d1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_DEADLINE_SUCCESS)); + + // cannot complete completed deadline + commandBox.runCommand("listall"); + commandBox.runCommand("complete d1"); + assertResultMessage(String.format(CompleteCommand.MESSAGE_COMPLETED_DEADLINE)); + + // complete with an invalid index + commandBox.runCommand("complete d200"); + assertResultMessage(String.format(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX)); + } + +} \ No newline at end of file diff --git a/src/test/java/guitests/DeleteCommandTest.java b/src/test/java/guitests/DeleteCommandTest.java index 10c7b9e0dbea..83462013f27e 100644 --- a/src/test/java/guitests/DeleteCommandTest.java +++ b/src/test/java/guitests/DeleteCommandTest.java @@ -1,54 +1,102 @@ package guitests; import org.junit.Test; -import seedu.address.testutil.TestPerson; -import seedu.address.testutil.TestUtil; -import static org.junit.Assert.assertTrue; -import static seedu.address.logic.commands.DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.logic.commands.DeleteCommand; +import seedu.malitio.testutil.TestDeadline; +import seedu.malitio.testutil.TestEvent; +import seedu.malitio.testutil.TestFloatingTask; +import seedu.malitio.testutil.TestUtil; -public class DeleteCommandTest extends AddressBookGuiTest { +import static org.junit.Assert.assertTrue; +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.malitio.logic.commands.DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS; +//@@author a0126633j +public class DeleteCommandTest extends MalitioGuiTest { + + private static final String FLOATING_TASK_KEYWORD = "f"; + private static final String DEADLINE_KEYWORD = "d"; + private static final String EVENT_KEYWORD = "e"; + @Test public void delete() { - //delete the first in the list - TestPerson[] currentList = td.getTypicalPersons(); + //Populate test tasks + TestFloatingTask[] floatingTaskList = td.getTypicalFloatingTasks(); + TestDeadline[] deadlineList = td.getTypicalDeadlines(); + TestEvent[] eventList = td.getTypicalEvents(); + + //invalid index argument + commandBox.runCommand("delete " + FLOATING_TASK_KEYWORD + floatingTaskList.length + 1); // boundary + assertResultMessage("The task index provided is invalid"); + commandBox.runCommand("delete " + EVENT_KEYWORD + 0); // boundary + assertResultMessage("The task index provided is invalid"); + commandBox.runCommand("delete " + "g1"); // invalid task type + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + + // to save resoures, work on each list because each list is identical + //delete first in floating task int targetIndex = 1; - assertDeleteSuccess(targetIndex, currentList); + assertDeleteSuccess(targetIndex, floatingTaskList); - //delete the last in the list - currentList = TestUtil.removePersonFromList(currentList, targetIndex); - targetIndex = currentList.length; - assertDeleteSuccess(targetIndex, currentList); + //delete the last in deadline + targetIndex = deadlineList.length; + assertDeleteSuccess(targetIndex, deadlineList); - //delete from the middle of the list - currentList = TestUtil.removePersonFromList(currentList, targetIndex); - targetIndex = currentList.length/2; - assertDeleteSuccess(targetIndex, currentList); + //delete from the middle of event list + targetIndex = eventList.length/2; + assertDeleteSuccess(targetIndex, eventList); - //invalid index - commandBox.runCommand("delete " + currentList.length + 1); - assertResultMessage("The person index provided is invalid"); } /** - * Runs the delete command to delete the person at specified index and confirms the result is correct. - * @param targetIndexOneIndexed e.g. to delete the first person in the list, 1 should be given as the target index. - * @param currentList A copy of the current list of persons (before deletion). + * Runs the delete command to delete the task at specified index and confirms the result is correct. + * (overloading functions for different tasks) + * @param targetIndexOneIndexed e.g. to delete the first task in the list, 1 should be given as the target index. + * @param task list: A copy of the current list of tasks (before deletion). */ - private void assertDeleteSuccess(int targetIndexOneIndexed, final TestPerson[] currentList) { - TestPerson personToDelete = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing - TestPerson[] expectedRemainder = TestUtil.removePersonFromList(currentList, targetIndexOneIndexed); + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestFloatingTask[] floatingTaskList) { + TestFloatingTask taskToDelete = floatingTaskList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestFloatingTask[] expectedRemainder = TestUtil.removeTasksFromList(floatingTaskList, targetIndexOneIndexed); - commandBox.runCommand("delete " + targetIndexOneIndexed); + commandBox.runCommand("delete " + FLOATING_TASK_KEYWORD + targetIndexOneIndexed); - //confirm the list now contains all previous persons except the deleted person - assertTrue(personListPanel.isListMatching(expectedRemainder)); + //confirm the list now contains all previous tasks except the deleted task + assertTrue(floatingTaskListPanel.isListMatching(expectedRemainder)); //confirm the result message is correct - assertResultMessage(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestDeadline[] deadlineList) { + TestDeadline taskToDelete = deadlineList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestDeadline[] expectedRemainder = TestUtil.removeTasksFromList(deadlineList, taskToDelete); + + commandBox.runCommand("delete " + DEADLINE_KEYWORD + targetIndexOneIndexed); + + assertTrue(deadlineListPanel.isListMatching(expectedRemainder)); + + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestEvent[] eventList) { + TestEvent taskToDelete = eventList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestEvent[] expectedRemainder = TestUtil.removeTasksFromList(eventList, taskToDelete); + + commandBox.runCommand("delete " + EVENT_KEYWORD + targetIndexOneIndexed); + + try { + assertTrue(eventListPanel.isListMatching(expectedRemainder)); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalValueException e) { + e.printStackTrace(); + } + + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); } } diff --git a/src/test/java/guitests/EditCommandTest.java b/src/test/java/guitests/EditCommandTest.java new file mode 100644 index 000000000000..6f52024f1c03 --- /dev/null +++ b/src/test/java/guitests/EditCommandTest.java @@ -0,0 +1,198 @@ +package guitests; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.logic.commands.EditCommand; +import seedu.malitio.testutil.TestDeadline; +import seedu.malitio.testutil.TestEvent; +import seedu.malitio.testutil.TestFloatingTask; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.testutil.TypicalTestTasks; +import org.junit.Test; + +import guitests.guihandles.DeadlineCardHandle; +import guitests.guihandles.EventCardHandle; +import guitests.guihandles.FloatingTaskCardHandle; + +import static org.junit.Assert.assertTrue; +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +//@@author A0129595N +public class EditCommandTest extends MalitioGuiTest { + + @Test + public void editFloatingtask() { + + // Edit name of floating task + TestFloatingTask[] currentList = td.getTypicalFloatingTasks(); + TestFloatingTask edited = TypicalTestTasks.editedFloatingTask1; + commandBox.runCommand("edit f1 how are you"); + assertEditSuccess(edited, 0, currentList); + + // Edit tags of floating task + edited = TypicalTestTasks.editedFloatingTask2; + commandBox.runCommand("edit f2 t/omg"); + assertEditSuccess(edited, 1, currentList); + + // Edit both name and tags of floating task + edited = TypicalTestTasks.editedFloatingTask3; + commandBox.runCommand("edit f3 Tell Nobody t/heello"); + assertEditSuccess(edited, 2, currentList); + + // Edit with an invalid index + commandBox.runCommand("edit f200"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + + // Edit a task to one which already exists + commandBox.runCommand("edit f1 Tell Nobody t/heello"); + assertResultMessage(EditCommand.MESSAGE_DUPLICATE_TASK); + } + + @Test + public void editDeadline() { + + // Edit name (only) of deadline + TestDeadline[] currentList = td.getTypicalDeadlines(); + TestDeadline toEdit = TypicalTestTasks.deadline1; + TestDeadline edited = TypicalTestTasks.editedDeadline1; + commandBox.runCommand("edit d1 Cut more hair "); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); // revert back to original state + + // Edit due date (only) of dateline + toEdit = TypicalTestTasks.deadline2; + edited = TypicalTestTasks.editedDeadline2; + commandBox.runCommand("edit d2 by 22 dec 12am"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit tag (only) of deadline + toEdit = TypicalTestTasks.deadline3; + edited = TypicalTestTasks.editedDeadline3; + commandBox.runCommand("edit d3 t/Pineapple t/Pen"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit name, duedate and tags of deadline + toEdit = TypicalTestTasks.deadline4; + edited = TypicalTestTasks.editedDeadline4; + commandBox.runCommand("edit d4 I want to sleep by 25 oct 11pm t/damntired"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit with an invalid index + commandBox.runCommand("edit d200"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + + // Edit a deadline to one which already exists + commandBox.runCommand("edit d1 Practice singing by 12-25 12am t/Christmas t/Carols"); + assertResultMessage(EditCommand.MESSAGE_DUPLICATE_DEADLINE); + } + + @Test + public void editEvent() { + + // Edit name (only) of event + TestEvent[] currentList = td.getTypicalEvents(); + TestEvent toEdit = TypicalTestTasks.event1; + TestEvent edited = TypicalTestTasks.editedEvent1; + commandBox.runCommand("edit e1 Eat with dad"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); // revert back to original state + + // Edit start (only) of event + toEdit = TypicalTestTasks.event2; + edited = TypicalTestTasks.editedEvent2; + commandBox.runCommand("edit e2 start 22 feb 2017 1pm"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit end (only) of event + toEdit = TypicalTestTasks.event3; + edited = TypicalTestTasks.editedEvent3; + commandBox.runCommand("edit e3 end 30 march 2017 9pm"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit tag (only) of event + toEdit = TypicalTestTasks.event4; + edited = TypicalTestTasks.editedEvent4; + commandBox.runCommand("edit e4 t/fun t/yahoo"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit name, start, end and tags of deadline + toEdit = TypicalTestTasks.event5; + edited = TypicalTestTasks.editedEvent5; + commandBox.runCommand("edit e5 Outing start 02-14-2017 10am end 02-14-2017 8pm t/dressup"); + assertEditSuccess(edited, toEdit, currentList); + commandBox.runCommand("undo"); + + // Edit with an invalid index + commandBox.runCommand("edit e200"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + + // Edit an event to one which already exists + commandBox.runCommand("edit e1 New year party start 12-31-2017 12am end 12-31-2017 11.59pm t/null"); + assertResultMessage(EditCommand.MESSAGE_DUPLICATE_EVENT); + + // Edit an event's start date later than end date + commandBox.runCommand("edit e5 start 12-26-2017"); + assertResultMessage(EditCommand.MESSAGE_INVALID_EVENT); + + } + + /** + * @param edited + * @param index + * @param currentList + */ + private void assertEditSuccess(TestFloatingTask edited, int index, TestFloatingTask... currentList) { + currentList = TestUtil.replaceTaskFromList(currentList, edited, index); + + //Confirm UI updated the card to match the edited details + FloatingTaskCardHandle addedCard = floatingTaskListPanel.navigateToTask(edited.getName().fullName); + assertMatching(edited, addedCard); + + //confirm the list now contain the edited floating task without the old floating task. + assertTrue(floatingTaskListPanel.isListMatching(currentList)); + } + + /** + * @param edited + * @param toEdit + * @param currentList + * @return updated TestDeadline array. + */ + private void assertEditSuccess(TestDeadline edited, TestDeadline toEdit, TestDeadline... currentList) { + currentList = TestUtil.removeTasksFromList(currentList, toEdit); + currentList = TestUtil.addTasksToList(currentList, edited); + + //Confirm UI updated the card to match the edited details + DeadlineCardHandle addedCard = deadlineListPanel.navigateToTask(edited.getName().fullName); + assertMatching(edited, addedCard); + + //confirm the list now contain the edited deadline without the old deadline. + assertTrue(deadlineListPanel.isListMatching(currentList)); + } + + /** + * @param edited + * @param toEdit + * @param currentList + * @return updated TestDeadline array. + */ + private void assertEditSuccess(TestEvent edited, TestEvent toEdit, TestEvent... currentList) { + currentList = TestUtil.removeTasksFromList(currentList, toEdit); + currentList = TestUtil.addTasksToList(currentList, edited); + try { + //Confirm UI updated the card to match the edited details + EventCardHandle addedCard = eventListPanel.navigateToTask(edited.getName().fullName); + assertMatching(edited, addedCard); + + //confirm the list now contain the edited deadline without the old deadline. + assertTrue(eventListPanel.isListMatching(currentList)); + } catch (IllegalArgumentException | IllegalValueException e) { + assert false : "Not possible"; + } + } + +} \ No newline at end of file diff --git a/src/test/java/guitests/FindCommandTest.java b/src/test/java/guitests/FindCommandTest.java index 441a6dbed666..b0ba68e4baee 100644 --- a/src/test/java/guitests/FindCommandTest.java +++ b/src/test/java/guitests/FindCommandTest.java @@ -1,39 +1,113 @@ package guitests; import org.junit.Test; -import seedu.address.commons.core.Messages; -import seedu.address.testutil.TestPerson; + +import seedu.malitio.testutil.TestDeadline; +import seedu.malitio.testutil.TestEvent; +import seedu.malitio.testutil.TestFloatingTask; +import seedu.malitio.commons.core.Messages; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.logic.commands.FindCommand; import static org.junit.Assert.assertTrue; +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -public class FindCommandTest extends AddressBookGuiTest { +//@@author a0126633j +public class FindCommandTest extends MalitioGuiTest { - @Test - public void find_nonEmptyList() { - assertFindResult("find Mark"); //no results - assertFindResult("find Meier", td.benson, td.daniel); //multiple results + //In the tests below, we assume event,floating task and deadline lists are identical, hence to save resources only work on them equally + @Test + public void find_nonEmptyList() throws IllegalArgumentException, IllegalValueException { + assertFindResult("find with", td.event1, td.event2); //multiple results + assertResultMessage("2 tasks found!"); + + commandBox.runCommand("list"); + assertFindResult("find peN HOMEWORK", td.floatingTask2, td.deadline3, td.deadline5); + assertResultMessage("3 tasks found!"); + + commandBox.runCommand("list"); + assertFindResult("find 25-dec", td.deadline4, td.event5); //find dates + assertResultMessage("2 tasks found!"); + + assertFindResult("find wedding"); //no result + //find after deleting one result - commandBox.runCommand("delete 1"); - assertFindResult("find Meier",td.daniel); + commandBox.runCommand("list"); + commandBox.runCommand("delete f1"); + assertFindResult("find bring",td.floatingTask2); } - + @Test - public void find_emptyList(){ + public void find_emptyList() throws IllegalArgumentException, IllegalValueException { commandBox.runCommand("clear"); - assertFindResult("find Jean"); //no results + assertFindResult("find eat"); //no result } @Test public void find_invalidCommand_fail() { - commandBox.runCommand("findgeorge"); + commandBox.runCommand("finddonothing"); assertResultMessage(Messages.MESSAGE_UNKNOWN_COMMAND); } + + @Test + public void find_specificTasks() throws IllegalArgumentException, IllegalValueException { + assertFindResult("find e with", td.event1, td.event2); //multiple results + assertResultMessage("2 tasks found!"); + + assertFindResult("find d H", td.deadline1, td.deadline4, td.deadline5); + assertResultMessage("3 tasks found!"); + + assertFindResult("find f tell", td.floatingTask3); + assertResultMessage("1 tasks found!"); + + commandBox.runCommand("find e"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); // recognise as finding in event but no keywords + } + + @Test + public void find_multipleFinds() throws IllegalArgumentException, IllegalValueException { + assertFindResult("find party with pen song", td.floatingTask2, td.floatingTask4, td.deadline3, + td.event1, td.event2, td.event5, td.event6); + assertResultMessage("7 tasks found!"); + + assertFindResult("find buy for mom", td.deadline3, td.event1, td.event2); + assertResultMessage("3 tasks found!"); + + assertFindResult("find 01-nov", td.deadline3); + assertResultMessage("1 tasks found!"); - private void assertFindResult(String command, TestPerson... expectedHits ) { + assertFindResult("find party"); + assertResultMessage("0 tasks found!"); + + commandBox.runCommand("list"); + assertFindResult("find party", td.event5, td.event6); + assertResultMessage("2 tasks found!"); + } + + /** + * Overload functions to assert result in each floating task, deadline and event list is correct + * @throws IllegalValueException + * @throws IllegalArgumentException + */ + + private void assertFindResult(String command, Object... expectedHits ) throws IllegalArgumentException, IllegalValueException { commandBox.runCommand(command); - assertListSize(expectedHits.length); - assertResultMessage(expectedHits.length + " persons listed!"); - assertTrue(personListPanel.isListMatching(expectedHits)); + + switch (expectedHits.getClass().getSimpleName()) { + case "TestFloatingTask": + assertFloatingTaskListSize(expectedHits.length); + assertTrue(floatingTaskListPanel.isListMatching((TestFloatingTask[]) expectedHits)); + break; + case "TestDeadline": + assertDeadlineListSize(expectedHits.length); + assertTrue(deadlineListPanel.isListMatching((TestDeadline[]) expectedHits)); + break; + case "TestEvent": + assertEventListSize(expectedHits.length); + assertTrue(eventListPanel.isListMatching((TestEvent[])expectedHits)); + break; + } } } diff --git a/src/test/java/guitests/GuiRobot.java b/src/test/java/guitests/GuiRobot.java index 44aa9edb48aa..eec321d58e14 100644 --- a/src/test/java/guitests/GuiRobot.java +++ b/src/test/java/guitests/GuiRobot.java @@ -2,7 +2,7 @@ import javafx.scene.input.KeyCodeCombination; import org.testfx.api.FxRobot; -import seedu.address.testutil.TestUtil; +import seedu.malitio.testutil.TestUtil; /** * Robot used to simulate user actions on the GUI. diff --git a/src/test/java/guitests/HelpWindowTest.java b/src/test/java/guitests/HelpWindowTest.java index 258d9d628d80..8477ccb6631f 100644 --- a/src/test/java/guitests/HelpWindowTest.java +++ b/src/test/java/guitests/HelpWindowTest.java @@ -5,12 +5,12 @@ import static org.junit.Assert.assertTrue; -public class HelpWindowTest extends AddressBookGuiTest { +public class HelpWindowTest extends MalitioGuiTest { @Test public void openHelpWindow() { - personListPanel.clickOnListView(); + floatingTaskListPanel.clickOnListView(); assertHelpWindowOpen(mainMenu.openHelpWindowUsingAccelerator()); diff --git a/src/test/java/guitests/ListAllCommandTest.java b/src/test/java/guitests/ListAllCommandTest.java new file mode 100644 index 000000000000..70e489b227ee --- /dev/null +++ b/src/test/java/guitests/ListAllCommandTest.java @@ -0,0 +1,23 @@ +package guitests; + +import org.junit.Test; + +import seedu.malitio.logic.commands.ListAllCommand; + +public class ListAllCommandTest extends MalitioGuiTest { + + @Test + public void completeFloatingtask() { + + //list all tasks from the beginning of time + commandBox.runCommand("listall"); + assertResultMessage(String.format(ListAllCommand.LISTALL_MESSAGE_SUCCESS)); + + + //list all tasks from the beginning of time + commandBox.runCommand("listall asdf"); + assertResultMessage(String.format(ListAllCommand.LISTALL_MESSAGE_SUCCESS)); + + } + +} diff --git a/src/test/java/guitests/ListCommandTest.java b/src/test/java/guitests/ListCommandTest.java new file mode 100644 index 000000000000..a8420e0de0cb --- /dev/null +++ b/src/test/java/guitests/ListCommandTest.java @@ -0,0 +1,126 @@ +package guitests; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +import seedu.malitio.commons.exceptions.IllegalValueException; + +public class ListCommandTest extends MalitioGuiTest { + + //@@author A0153006W + @Test + public void list() { + + //verify list shows all items after panels are empty + commandBox.runCommand("find x"); + assertListCommandSuccess(); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + assertTrue(deadlineListPanel.isListMatching(td.getTypicalDeadlines())); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + e.printStackTrace(); + } + } + + @Test + public void listTasks() { + + //verify list tasks only updates the tasks panel + commandBox.runCommand("find x"); + assertListCommandSuccess("floating tasks"); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + assertDeadlineListSize(0); + assertEventListSize(0); + + //verify list tasks [DATETIME] updates to all floating tasks + commandBox.runCommand("find x"); + assertListCommandSuccess("floating tasks", "10-31 2am"); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + } + + @Test + public void listDeadlines() { + + //verify list deadlines only updates the deadlines panel + commandBox.runCommand("find x"); + assertListCommandSuccess("deadlines"); + assertTrue(deadlineListPanel.isListMatching(td.getTypicalDeadlines())); + assertFloatingTaskListSize(0); + assertEventListSize(0); + + //verify list deadlines [DATETIME] updates to deadlines with due dates on or after [DATETIME] + assertListCommandSuccess(); + assertListCommandSuccess("deadlines", "12-27 midnight"); + assertTrue(deadlineListPanel.isListMatching(td.deadline5)); + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + } + + @Test + public void listEvents() { + + //verify list events only updates the events panel + commandBox.runCommand("find x"); + assertListCommandSuccess("events"); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + assertFloatingTaskListSize(0); + assertDeadlineListSize(0); + + //verify list events [DATETIME] updates to events that start on or after [DATETIME] + assertListCommandSuccess(); + assertListCommandSuccess("events", "12-31-17 0000"); + try { + assertTrue(eventListPanel.isListMatching(td.event6)); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + assertTrue(floatingTaskListPanel.isListMatching(td.getTypicalFloatingTasks())); + assertTrue(deadlineListPanel.isListMatching(td.getTypicalDeadlines())); + } + + @Test + public void listDateTime() { + + //verify list [DATETIME] updates both deadlines and events + commandBox.runCommand("find x"); + assertListCommandSuccess("", "12-27"); + assertFloatingTaskListSize(0); + assertTrue(deadlineListPanel.isListMatching(td.deadline5)); + try { + assertTrue(eventListPanel.isListMatching(td.getTypicalEvents())); + } catch (IllegalArgumentException | IllegalValueException e) { + fail(); + } + } + + private void assertListCommandSuccess() { + commandBox.runCommand("list"); + assertResultMessage("Listed all tasks"); + } + + private void assertListCommandSuccess(String taskType) { + commandBox.runCommand("list " + taskType); + assertResultMessage("Listed " + taskType); + } + + private void assertListCommandSuccess(String taskType, String dateTime) { + commandBox.runCommand("list " + taskType + " " + dateTime); + if (taskType.isEmpty()) { + assertResultMessage("Listed all tasks"); + } + else { + assertResultMessage("Listed " + taskType); + } + } +} diff --git a/src/test/java/guitests/AddressBookGuiTest.java b/src/test/java/guitests/MalitioGuiTest.java similarity index 51% rename from src/test/java/guitests/AddressBookGuiTest.java rename to src/test/java/guitests/MalitioGuiTest.java index 35734932f11c..72c951bd549e 100644 --- a/src/test/java/guitests/AddressBookGuiTest.java +++ b/src/test/java/guitests/MalitioGuiTest.java @@ -8,12 +8,14 @@ import org.junit.Rule; import org.junit.rules.TestName; import org.testfx.api.FxToolkit; -import seedu.address.TestApp; -import seedu.address.commons.core.EventsCenter; -import seedu.address.model.AddressBook; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.testutil.TestUtil; -import seedu.address.testutil.TypicalTestPersons; +import seedu.malitio.TestApp; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.testutil.TypicalTestTasks; +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.task.ReadOnlyDeadline; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; import java.util.concurrent.TimeoutException; @@ -21,9 +23,9 @@ import static org.junit.Assert.assertTrue; /** - * A GUI Test class for AddressBook. + * A GUI Test class for malitio. */ -public abstract class AddressBookGuiTest { +public abstract class MalitioGuiTest { /* The TestName Rule makes the current test name available inside test methods */ @Rule @@ -31,7 +33,7 @@ public abstract class AddressBookGuiTest { TestApp testApp; - protected TypicalTestPersons td = new TypicalTestPersons(); + protected TypicalTestTasks td = new TypicalTestTasks(); /* * Handles to GUI elements present at the start up are created in advance @@ -39,7 +41,9 @@ public abstract class AddressBookGuiTest { */ protected MainGuiHandle mainGui; protected MainMenuHandle mainMenu; - protected PersonListPanelHandle personListPanel; + protected FloatingTaskListPanelHandle floatingTaskListPanel; + protected DeadlineListPanelHandle deadlineListPanel; + protected EventListPanelHandle eventListPanel; protected ResultDisplayHandle resultDisplay; protected CommandBoxHandle commandBox; private Stage stage; @@ -59,7 +63,9 @@ public void setup() throws Exception { FxToolkit.setupStage((stage) -> { mainGui = new MainGuiHandle(new GuiRobot(), stage); mainMenu = mainGui.getMainMenu(); - personListPanel = mainGui.getPersonListPanel(); + floatingTaskListPanel = mainGui.getFloatingTaskListPanel(); + deadlineListPanel = mainGui.getDeadlineListPanel(); + eventListPanel = mainGui.getEventListPanel(); resultDisplay = mainGui.getResultDisplay(); commandBox = mainGui.getCommandBox(); this.stage = stage; @@ -75,9 +81,9 @@ public void setup() throws Exception { * Override this in child classes to set the initial local data. * Return null to use the data in the file specified in {@link #getDataFileLocation()} */ - protected AddressBook getInitialData() { - AddressBook ab = TestUtil.generateEmptyAddressBook(); - TypicalTestPersons.loadAddressBookWithSampleData(ab); + protected Malitio getInitialData() { + Malitio ab = TestUtil.generateEmptymalitio(); + TypicalTestTasks.loadMalitioWithSampleData(ab); return ab; } @@ -94,20 +100,41 @@ public void cleanup() throws TimeoutException { } /** - * Asserts the person shown in the card is same as the given person + * Asserts the task shown in the card is same as the given task */ - public void assertMatching(ReadOnlyPerson person, PersonCardHandle card) { - assertTrue(TestUtil.compareCardAndPerson(card, person)); + public void assertMatching(ReadOnlyFloatingTask task, FloatingTaskCardHandle card) { + assertTrue(TestUtil.compareCardAndTask(card, task)); } - + public void assertMatching(ReadOnlyDeadline task, DeadlineCardHandle card) { + assertTrue(TestUtil.compareCardAndTask(card, task)); + } + public void assertMatching(ReadOnlyEvent task, EventCardHandle card) { + assertTrue(TestUtil.compareCardAndTask(card, task)); + } + /** - * Asserts the size of the person list is equal to the given number. + * Asserts the size of the total list is equal to the given number. */ - protected void assertListSize(int size) { - int numberOfPeople = personListPanel.getNumberOfPeople(); - assertEquals(size, numberOfPeople); + protected void assertTotalListSize(int size) { + int numberOfTasks = + floatingTaskListPanel.getNumberOfTasks() + + deadlineListPanel.getNumberOfTasks() + + eventListPanel.getNumberOfTasks(); + assertEquals(size, numberOfTasks); } + protected void assertFloatingTaskListSize(int size) { + int numberOfTasks = floatingTaskListPanel.getNumberOfTasks(); + assertEquals(size, numberOfTasks); + } + protected void assertDeadlineListSize(int size) { + int numberOfTasks = deadlineListPanel.getNumberOfTasks(); + assertEquals(size, numberOfTasks); + } + protected void assertEventListSize(int size) { + int numberOfTasks = eventListPanel.getNumberOfTasks(); + assertEquals(size, numberOfTasks); + } /** * Asserts the message shown in the Result Display area is same as the given string. */ diff --git a/src/test/java/guitests/SaveCommandTest.java b/src/test/java/guitests/SaveCommandTest.java new file mode 100644 index 000000000000..738b110be3d4 --- /dev/null +++ b/src/test/java/guitests/SaveCommandTest.java @@ -0,0 +1,87 @@ +package guitests; + +import java.io.File; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.ConfigUtil; +import seedu.malitio.logic.commands.SaveCommand; +import seedu.malitio.model.Malitio; +import seedu.malitio.storage.StorageManager; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +//@@author a0126633j +/** + * Assumes storage and file utils are working + * + */ + +public class SaveCommandTest extends MalitioGuiTest { + private static final String DEFAULT_FILE_NAME = "malitio.xml"; + private static final String TEST_FILE_PATH = "src/test/data/tempDataForSaveCommand/test1/"; + private static final String DEFAULT_FILE_PATH = "src/test/data/tempDataForSaveCommand/"; + + // a storage manager to read data from xml file + private StorageManager storageManager = new StorageManager("random", "random"); + + private Malitio original = getInitialData(); + private String originalFilePath; + + @Before + public void getOriginalFilePath() throws DataConversionException { + originalFilePath = ConfigUtil.readConfig("./config.json/").get().getMalitioFilePath(); + } + + @Test + public void save() throws DataConversionException, IOException { + + //save default file location + commandBox.runCommand("save " + DEFAULT_FILE_PATH); + assertSaveSuccessful(DEFAULT_FILE_PATH); + + //save in new file location + commandBox.runCommand("save " + TEST_FILE_PATH); + assertSaveSuccessful(TEST_FILE_PATH); + assertFileDeletionSuccessful(DEFAULT_FILE_PATH); + + //save default file location again but with back slash + commandBox.runCommand("save " + "src\\test\\data\\tempDataForSaveCommand\\"); + assertSaveSuccessful("src\\test\\data\\tempDataForSaveCommand\\"); + assertFileDeletionSuccessful(TEST_FILE_PATH); + + //invalid file path + commandBox.runCommand("save abc"); + assertResultMessage(SaveCommand.MESSAGE_INVALID_DIRECTORY + SaveCommand.MESSAGE_DIRECTORY_EXAMPLE); + + //orginal save file location should be preserved after the tests + ConfigUtil.changeMalitioSaveDirectory(originalFilePath); + } + + /** + * Asserts new file is present and consistent with Malitio data + * @throws DataConversionException + * @throws IOException + */ + public void assertSaveSuccessful(String newFileLocation) throws DataConversionException, IOException { + File f = new File(newFileLocation + DEFAULT_FILE_NAME); + if(f.exists()) { + assertEquals(original, new Malitio(storageManager.readMalitio(newFileLocation + DEFAULT_FILE_NAME).get())); + assertResultMessage(String.format(SaveCommand.MESSAGE_SAVE_SUCCESSFUL, newFileLocation + DEFAULT_FILE_NAME)); + } else { + assertTrue(false); + } + } + + /** + * Asserts old file is successfully deleted + */ + public void assertFileDeletionSuccessful(String oldFileLocation) { + File f = new File(oldFileLocation + DEFAULT_FILE_NAME); + assertFalse(f.exists()); + } +} \ No newline at end of file diff --git a/src/test/java/guitests/SelectCommandTest.java b/src/test/java/guitests/SelectCommandTest.java deleted file mode 100644 index 5273552056ce..000000000000 --- a/src/test/java/guitests/SelectCommandTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package guitests; - -import org.junit.Test; -import seedu.address.model.person.ReadOnlyPerson; - -import static org.junit.Assert.assertEquals; - -public class SelectCommandTest extends AddressBookGuiTest { - - - @Test - public void selectPerson_nonEmptyList() { - - assertSelectionInvalid(10); //invalid index - assertNoPersonSelected(); - - assertSelectionSuccess(1); //first person in the list - int personCount = td.getTypicalPersons().length; - assertSelectionSuccess(personCount); //last person in the list - int middleIndex = personCount / 2; - assertSelectionSuccess(middleIndex); //a person in the middle of the list - - assertSelectionInvalid(personCount + 1); //invalid index - assertPersonSelected(middleIndex); //assert previous selection remains - - /* Testing other invalid indexes such as -1 should be done when testing the SelectCommand */ - } - - @Test - public void selectPerson_emptyList(){ - commandBox.runCommand("clear"); - assertListSize(0); - assertSelectionInvalid(1); //invalid index - } - - private void assertSelectionInvalid(int index) { - commandBox.runCommand("select " + index); - assertResultMessage("The person index provided is invalid"); - } - - private void assertSelectionSuccess(int index) { - commandBox.runCommand("select " + index); - assertResultMessage("Selected Person: "+index); - assertPersonSelected(index); - } - - private void assertPersonSelected(int index) { - assertEquals(personListPanel.getSelectedPersons().size(), 1); - ReadOnlyPerson selectedPerson = personListPanel.getSelectedPersons().get(0); - assertEquals(personListPanel.getPerson(index-1), selectedPerson); - //TODO: confirm the correct page is loaded in the Browser Panel - } - - private void assertNoPersonSelected() { - assertEquals(personListPanel.getSelectedPersons().size(), 0); - } - -} diff --git a/src/test/java/guitests/UncompleteCommandTest.java b/src/test/java/guitests/UncompleteCommandTest.java new file mode 100644 index 000000000000..253c70c6c078 --- /dev/null +++ b/src/test/java/guitests/UncompleteCommandTest.java @@ -0,0 +1,48 @@ +package guitests; + +import seedu.malitio.commons.core.Messages; +import seedu.malitio.logic.commands.UncompleteCommand; + +import org.junit.Test; +import static seedu.malitio.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +//@@author A0122460W +public class UncompleteCommandTest extends MalitioGuiTest { + + @Test + public void uncompleteFloatingtask() { + + // cannot uncomplete a uncompleted floating task + commandBox.runCommand("uncomplete f1"); + assertResultMessage(String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_TASK)); + + // uncomplete floating task + commandBox.runCommand("complete f1"); + commandBox.runCommand("uncomplete f1"); + assertResultMessage(String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_TASK_SUCCESS)); + + // uncomplete error command + commandBox.runCommand("uncomplete"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UncompleteCommand.MESSAGE_USAGE)); + + commandBox.runCommand("uncomplete asdf"); + assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT, UncompleteCommand.MESSAGE_USAGE)); + + // uncomplete with an invalid index + commandBox.runCommand("uncomplete f200"); + assertResultMessage(String.format(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX)); + } + + @Test + public void uncompleteDeadline() { + + // cannot uncomplete a uncompleted deadline + commandBox.runCommand("uncomplete d1"); + assertResultMessage(String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_DEADLINE)); + + // uncomplete with an invalid index + commandBox.runCommand("uncomplete d200"); + assertResultMessage(String.format(Messages.MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX)); + } + +} \ No newline at end of file diff --git a/src/test/java/guitests/guihandles/DeadlineCardHandle.java b/src/test/java/guitests/guihandles/DeadlineCardHandle.java new file mode 100644 index 000000000000..e54080fe59da --- /dev/null +++ b/src/test/java/guitests/guihandles/DeadlineCardHandle.java @@ -0,0 +1,53 @@ +package guitests.guihandles; + +import guitests.GuiRobot; +import javafx.scene.Node; +import javafx.stage.Stage; +import seedu.malitio.model.task.ReadOnlyDeadline; + +/** + * Provides a handle to a deadline card in the task list panel. + */ +public class DeadlineCardHandle extends GuiHandle { + + private static final String NAME_FIELD_ID = "#name"; + private static final String DUE_FIELD_ID = "#due"; + + private Node node; + + public DeadlineCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ + super(guiRobot, primaryStage, null); + this.node = node; + } + + protected String getTextFromLabel(String fieldId) { + return getTextFromLabel(fieldId, node); + } + + public String getFullName() { + return getTextFromLabel(NAME_FIELD_ID); + } + + public String getDue() { + return getTextFromLabel(DUE_FIELD_ID); + } + + public boolean isSameDeadline(ReadOnlyDeadline deadline) { + return getFullName().equals(deadline.getName().fullName) && getDue().substring(5).equals(deadline.getDue().toString()); + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof DeadlineCardHandle) { + DeadlineCardHandle handle = (DeadlineCardHandle) obj; + return getFullName().equals(handle.getFullName()) && getDue().equals(handle.getDue()); + } + return super.equals(obj); + } + + @Override + public String toString() { + return getFullName(); + } +} + diff --git a/src/test/java/guitests/guihandles/DeadlineListPanelHandle.java b/src/test/java/guitests/guihandles/DeadlineListPanelHandle.java new file mode 100644 index 000000000000..cc5d7a1831b1 --- /dev/null +++ b/src/test/java/guitests/guihandles/DeadlineListPanelHandle.java @@ -0,0 +1,173 @@ +package guitests.guihandles; + + +import guitests.GuiRobot; +import javafx.geometry.Point2D; +import javafx.scene.Node; +import javafx.scene.control.ListView; +import javafx.stage.Stage; +import seedu.malitio.TestApp; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.ReadOnlyDeadline; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +/** + * Provides a handle for the panel containing the deadline list. + */ +public class DeadlineListPanelHandle extends GuiHandle { + + public static final int NOT_FOUND = -1; + public static final String CARD_PANE_ID = "#cardPane2"; + + private static final String DEADLINE_LIST_VIEW_ID = "#deadlineListView"; + + public DeadlineListPanelHandle(GuiRobot guiRobot, Stage primaryStage) { + super(guiRobot, primaryStage, TestApp.APP_TITLE); + } + + public List getSelectedTasks() { + ListView taskList = getListView(); + return taskList.getSelectionModel().getSelectedItems(); + } + + public ListView getListView() { + return (ListView) getNode(DEADLINE_LIST_VIEW_ID); + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param tasks A list of task in the correct order. + */ + public boolean isListMatching(ReadOnlyDeadline... tasks) { + return this.isListMatching(0, tasks); + } + + /** + * Clicks on the ListView. + */ + public void clickOnListView() { + Point2D point= TestUtil.getScreenMidPoint(getListView()); + guiRobot.clickOn(point.getX(), point.getY()); + } + + /** + * Returns true if the {@code tasks} appear as the sub list (in that order) at position {@code startPosition}. + */ + public boolean containsInOrder(int startPosition, ReadOnlyDeadline... tasks) { + List tasksInList = getListView().getItems(); + + // Return false if the list in panel is too short to contain the given list + if (startPosition + tasks.length > tasksInList.size()){ + return false; + } + + // Return false if any of the tasks doesn't match + for (int i = 0; i < tasks.length; i++) { + if (!tasksInList.get(startPosition + i).getName().fullName.equals(tasks[i].getName().fullName) + || !tasksInList.get(startPosition + i).getDue().toString().equals(tasks[i].getDue().toString()) + || !tasksInList.get(startPosition + i).getTags().toSet().equals(tasks[i].getTags().toSet())) { + return false; + } + } + + return true; + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param startPosition The starting position of the sub list. + * @param tasks A list of task in the correct order. + */ + public boolean isListMatching(int startPosition, ReadOnlyDeadline... tasks) throws IllegalArgumentException { + if (tasks.length + startPosition != getListView().getItems().size()) { + throw new IllegalArgumentException("List size mismatched\n" + + "Expected " + (getListView().getItems().size() - 1) + " tasks"); + } + assertTrue(this.containsInOrder(startPosition, tasks)); + for (int i = 0; i < tasks.length; i++) { + final int scrollTo = i + startPosition; + guiRobot.interact(() -> getListView().scrollTo(scrollTo)); + guiRobot.sleep(200); + if (!TestUtil.compareCardAndTask(getTaskCardHandle(startPosition + i), tasks[i])) { + return false; + } + } + return true; + } + + + public DeadlineCardHandle navigateToTask(String name) { + guiRobot.sleep(500); //Allow a bit of time for the list to be updated + final Optional task = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); + if (!task.isPresent()) { + throw new IllegalStateException("Name not found: " + name); + } + + return navigateToTask(task.get()); + } + + /** + * Navigates the listview to display and select the task. + */ + public DeadlineCardHandle navigateToTask(ReadOnlyDeadline task) { + int index = getTaskIndex(task); + + guiRobot.interact(() -> { + getListView().scrollTo(index); + guiRobot.sleep(150); + getListView().getSelectionModel().select(index); + }); + guiRobot.sleep(100); + return getTaskCardHandle(task); + } + + + /** + * Returns the position of the task given, {@code NOT_FOUND} if not found in the list. + */ + public int getTaskIndex(ReadOnlyDeadline targetTask) { + List tasksInList = getListView().getItems(); + for (int i = 0; i < tasksInList.size(); i++) { + if(tasksInList.get(i).getName().equals(targetTask.getName())){ + return i; + } + } + return NOT_FOUND; + } + + /** + * Gets a task from the list by index + */ + public ReadOnlyDeadline getTask(int index) { + return getListView().getItems().get(index); + } + + public DeadlineCardHandle getTaskCardHandle(int index) { + return getTaskCardHandle(new Deadline(getListView().getItems().get(index))); + } + + public DeadlineCardHandle getTaskCardHandle(ReadOnlyDeadline task) { + Set nodes = getAllCardNodes(); + Optional taskCardNode = nodes.stream() + .filter(n -> new DeadlineCardHandle(guiRobot, primaryStage, n).isSameDeadline(task)) + .findFirst(); + if (taskCardNode.isPresent()) { + return new DeadlineCardHandle(guiRobot, primaryStage, taskCardNode.get()); + } else { + return null; + } + } + + protected Set getAllCardNodes() { + return guiRobot.lookup(CARD_PANE_ID).queryAll(); + } + + public int getNumberOfTasks() { + return getListView().getItems().size(); + } +} diff --git a/src/test/java/guitests/guihandles/EventCardHandle.java b/src/test/java/guitests/guihandles/EventCardHandle.java new file mode 100644 index 000000000000..f343a6ae02e5 --- /dev/null +++ b/src/test/java/guitests/guihandles/EventCardHandle.java @@ -0,0 +1,64 @@ +package guitests.guihandles; + +import guitests.GuiRobot; +import javafx.scene.Node; +import javafx.stage.Stage; +import seedu.malitio.model.task.ReadOnlyEvent; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +/** + * Provides a handle to a Event card in the task list panel. + */ +public class EventCardHandle extends GuiHandle { + + private static final String NAME_FIELD_ID = "#name"; + private static final String START_FIELD_ID = "#start"; + private static final String END_FIELD_ID = "#end"; + + private Node node; + + public EventCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ + super(guiRobot, primaryStage, null); + this.node = node; + } + + protected String getTextFromLabel(String fieldId) { + return getTextFromLabel(fieldId, node); + } + + public String getFullName() { + return getTextFromLabel(NAME_FIELD_ID); + } + + public String getStart() { + return getTextFromLabel(START_FIELD_ID); + } + + public String getEnd() { + return getTextFromLabel(END_FIELD_ID); + } + + public boolean isSameTask(ReadOnlyEvent event){ + return getFullName().equals(event.getName().fullName) + && getStart().substring(7).equals(event.getStart().toString()) + && getEnd().substring(5).equals(event.getEnd().toString()); + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof EventCardHandle) { + EventCardHandle handle = (EventCardHandle) obj; + return getFullName().equals(handle.getFullName()) + && getStart().equals(handle.getStart()) + && getEnd().equals(handle.getEnd()); + } + return super.equals(obj); + } + + @Override + public String toString() { + return getFullName(); + } +} + + diff --git a/src/test/java/guitests/guihandles/EventListPanelHandle.java b/src/test/java/guitests/guihandles/EventListPanelHandle.java new file mode 100644 index 000000000000..785e594b4520 --- /dev/null +++ b/src/test/java/guitests/guihandles/EventListPanelHandle.java @@ -0,0 +1,178 @@ +package guitests.guihandles; + + +import guitests.GuiRobot; +import javafx.geometry.Point2D; +import javafx.scene.Node; +import javafx.scene.control.ListView; +import javafx.stage.Stage; +import seedu.malitio.TestApp; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.model.task.Event; +import seedu.malitio.model.task.ReadOnlyEvent; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +/** + * Provides a handle for the panel containing the event list. + */ +public class EventListPanelHandle extends GuiHandle { + + public static final int NOT_FOUND = -1; + public static final String CARD_PANE_ID = "#cardPane3"; + + private static final String EVENT_LIST_VIEW_ID = "#eventListView"; + + public EventListPanelHandle(GuiRobot guiRobot, Stage primaryStage) { + super(guiRobot, primaryStage, TestApp.APP_TITLE); + } + + public List getSelectedTasks() { + ListView taskList = getListView(); + return taskList.getSelectionModel().getSelectedItems(); + } + + public ListView getListView() { + return (ListView) getNode(EVENT_LIST_VIEW_ID); + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param tasks A list of task in the correct order. + * @throws IllegalValueException + * @throws IllegalArgumentException + */ + public boolean isListMatching(ReadOnlyEvent... tasks) throws IllegalArgumentException, IllegalValueException { + return this.isListMatching(0, tasks); + } + + /** + * Clicks on the ListView. + */ + public void clickOnListView() { + Point2D point= TestUtil.getScreenMidPoint(getListView()); + guiRobot.clickOn(point.getX(), point.getY()); + } + + /** + * Returns true if the {@code tasks} appear as the sub list (in that order) at position {@code startPosition}. + */ + public boolean containsInOrder(int startPosition, ReadOnlyEvent... tasks) { + List tasksInList = getListView().getItems(); + + // Return false if the list in panel is too short to contain the given list + if (startPosition + tasks.length > tasksInList.size()){ + return false; + } + + // Return false if any of the tasks doesn't match + for (int i = 0; i < tasks.length; i++) { + if (!tasksInList.get(startPosition + i).getName().fullName.equals(tasks[i].getName().fullName) + || !tasksInList.get(startPosition + i).getStart().toString().equals(tasks[i].getStart().toString()) + || !tasksInList.get(startPosition + i).getEnd().toString().equals(tasks[i].getEnd().toString()) + || !tasksInList.get(startPosition + i).getTags().toSet().equals(tasks[i].getTags().toSet())) { + return false; + } + } + + return true; + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param startPosition The starting position of the sub list. + * @param tasks A list of task in the correct order. + * @throws IllegalValueException + */ + public boolean isListMatching(int startPosition, ReadOnlyEvent... tasks) throws IllegalArgumentException, IllegalValueException { + if (tasks.length + startPosition != getListView().getItems().size()) { + throw new IllegalArgumentException("List size mismatched\n" + + "Expected " + (getListView().getItems().size() - 1) + " tasks"); + } + assertTrue(this.containsInOrder(startPosition, tasks)); + for (int i = 0; i < tasks.length; i++) { + final int scrollTo = i + startPosition; + guiRobot.interact(() -> getListView().scrollTo(scrollTo)); + guiRobot.sleep(200); + if (!TestUtil.compareCardAndTask(getTaskCardHandle(startPosition + i), tasks[i])) { + return false; + } + } + return true; + } + + + public EventCardHandle navigateToTask(String name) { + guiRobot.sleep(500); //Allow a bit of time for the list to be updated + final Optional task = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); + if (!task.isPresent()) { + throw new IllegalStateException("Name not found: " + name); + } + + return navigateToTask(task.get()); + } + + /** + * Navigates the listview to display and select the task. + */ + public EventCardHandle navigateToTask(ReadOnlyEvent task) { + int index = getTaskIndex(task); + + guiRobot.interact(() -> { + getListView().scrollTo(index); + guiRobot.sleep(150); + getListView().getSelectionModel().select(index); + }); + guiRobot.sleep(100); + return getTaskCardHandle(task); + } + + + /** + * Returns the position of the task given, {@code NOT_FOUND} if not found in the list. + */ + public int getTaskIndex(ReadOnlyEvent targetTask) { + List tasksInList = getListView().getItems(); + for (int i = 0; i < tasksInList.size(); i++) { + if(tasksInList.get(i).getName().equals(targetTask.getName())){ + return i; + } + } + return NOT_FOUND; + } + + /** + * Gets a task from the list by index + */ + public ReadOnlyEvent getTask(int index) { + return getListView().getItems().get(index); + } + + public EventCardHandle getTaskCardHandle(int index) throws IllegalValueException { + return getTaskCardHandle(new Event(getListView().getItems().get(index))); + } + + public EventCardHandle getTaskCardHandle(ReadOnlyEvent task) { + Set nodes = getAllCardNodes(); + Optional taskCardNode = nodes.stream() + .filter(n -> new EventCardHandle(guiRobot, primaryStage, n).isSameTask(task)) + .findFirst(); + if (taskCardNode.isPresent()) { + return new EventCardHandle(guiRobot, primaryStage, taskCardNode.get()); + } else { + return null; + } + } + + protected Set getAllCardNodes() { + return guiRobot.lookup(CARD_PANE_ID).queryAll(); + } + + public int getNumberOfTasks() { + return getListView().getItems().size(); + } +} diff --git a/src/test/java/guitests/guihandles/FloatingTaskCardHandle.java b/src/test/java/guitests/guihandles/FloatingTaskCardHandle.java new file mode 100644 index 000000000000..c7fd7cdd4fc4 --- /dev/null +++ b/src/test/java/guitests/guihandles/FloatingTaskCardHandle.java @@ -0,0 +1,46 @@ +package guitests.guihandles; + +import guitests.GuiRobot; +import javafx.scene.Node; +import javafx.stage.Stage; +import seedu.malitio.model.task.ReadOnlyFloatingTask; + +/** + * Provides a handle to a floating task card in the task list panel. + */ +public class FloatingTaskCardHandle extends GuiHandle { + private static final String NAME_FIELD_ID = "#name"; + + private Node node; + + public FloatingTaskCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ + super(guiRobot, primaryStage, null); + this.node = node; + } + + protected String getTextFromLabel(String fieldId) { + return getTextFromLabel(fieldId, node); + } + + public String getFullName() { + return getTextFromLabel(NAME_FIELD_ID); + } + + public boolean isSameTask(ReadOnlyFloatingTask task){ + return getFullName().equals(task.getName().fullName); + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof FloatingTaskCardHandle) { + FloatingTaskCardHandle handle = (FloatingTaskCardHandle) obj; + return getFullName().equals(handle.getFullName()); + } + return super.equals(obj); + } + + @Override + public String toString() { + return getFullName(); + } +} diff --git a/src/test/java/guitests/guihandles/FloatingTaskListPanelHandle.java b/src/test/java/guitests/guihandles/FloatingTaskListPanelHandle.java new file mode 100644 index 000000000000..20a55ec9a861 --- /dev/null +++ b/src/test/java/guitests/guihandles/FloatingTaskListPanelHandle.java @@ -0,0 +1,172 @@ +package guitests.guihandles; + + +import guitests.GuiRobot; +import javafx.geometry.Point2D; +import javafx.scene.Node; +import javafx.scene.control.ListView; +import javafx.stage.Stage; +import seedu.malitio.TestApp; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.model.task.FloatingTask; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +/** + * Provides a handle for the panel containing the floating task list. + */ +public class FloatingTaskListPanelHandle extends GuiHandle { + + public static final int NOT_FOUND = -1; + public static final String CARD_PANE_ID = "#cardPane"; + + private static final String TASK_LIST_VIEW_ID = "#taskListView"; + + public FloatingTaskListPanelHandle(GuiRobot guiRobot, Stage primaryStage) { + super(guiRobot, primaryStage, TestApp.APP_TITLE); + } + + public List getSelectedTasks() { + ListView taskList = getListView(); + return taskList.getSelectionModel().getSelectedItems(); + } + + public ListView getListView() { + return (ListView) getNode(TASK_LIST_VIEW_ID); + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param tasks A list of task in the correct order. + */ + public boolean isListMatching(ReadOnlyFloatingTask... tasks) { + return this.isListMatching(0, tasks); + } + + /** + * Clicks on the ListView. + */ + public void clickOnListView() { + Point2D point= TestUtil.getScreenMidPoint(getListView()); + guiRobot.clickOn(point.getX(), point.getY()); + } + + /** + * Returns true if the {@code tasks} appear as the sub list (in that order) at position {@code startPosition}. + */ + public boolean containsInOrder(int startPosition, ReadOnlyFloatingTask... tasks) { + List tasksInList = getListView().getItems(); + + // Return false if the list in panel is too short to contain the given list + if (startPosition + tasks.length > tasksInList.size()){ + return false; + } + + // Return false if any of the tasks doesn't match + for (int i = 0; i < tasks.length; i++) { + if (!tasksInList.get(startPosition + i).getName().fullName.equals(tasks[i].getName().fullName) + || !tasksInList.get(startPosition + i).getTags().equals(tasks[i].getTags())){ + return false; + } + } + + return true; + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param startPosition The starting position of the sub list. + * @param tasks A list of task in the correct order. + */ + public boolean isListMatching(int startPosition, ReadOnlyFloatingTask... tasks) throws IllegalArgumentException { + if (tasks.length + startPosition != getListView().getItems().size()) { + throw new IllegalArgumentException("List size mismatched\n" + + "Expected " + (getListView().getItems().size() - 1) + " tasks"); + } + assertTrue(this.containsInOrder(startPosition, tasks)); + for (int i = 0; i < tasks.length; i++) { + final int scrollTo = i + startPosition; + guiRobot.interact(() -> getListView().scrollTo(scrollTo)); + guiRobot.sleep(200); + if (!TestUtil.compareCardAndTask(getTaskCardHandle(startPosition + i), tasks[i])) { + return false; + } + } + return true; + } + + + public FloatingTaskCardHandle navigateToTask(String name) { + guiRobot.sleep(500); //Allow a bit of time for the list to be updated + final Optional task = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); + if (!task.isPresent()) { + throw new IllegalStateException("Name not found: " + name); + } + + return navigateToTask(task.get()); + } + + /** + * Navigates the listview to display and select the task. + */ + public FloatingTaskCardHandle navigateToTask(ReadOnlyFloatingTask task) { + int index = getTaskIndex(task); + + guiRobot.interact(() -> { + getListView().scrollTo(index); + guiRobot.sleep(150); + getListView().getSelectionModel().select(index); + }); + guiRobot.sleep(100); + return getTaskCardHandle(task); + } + + + /** + * Returns the position of the task given, {@code NOT_FOUND} if not found in the list. + */ + public int getTaskIndex(ReadOnlyFloatingTask targetTask) { + List tasksInList = getListView().getItems(); + for (int i = 0; i < tasksInList.size(); i++) { + if(tasksInList.get(i).getName().equals(targetTask.getName())){ + return i; + } + } + return NOT_FOUND; + } + + /** + * Gets a task from the list by index + */ + public ReadOnlyFloatingTask getTask(int index) { + return getListView().getItems().get(index); + } + + public FloatingTaskCardHandle getTaskCardHandle(int index) { + return getTaskCardHandle(new FloatingTask(getListView().getItems().get(index))); + } + + public FloatingTaskCardHandle getTaskCardHandle(ReadOnlyFloatingTask task) { + Set nodes = getAllCardNodes(); + Optional taskCardNode = nodes.stream() + .filter(n -> new FloatingTaskCardHandle(guiRobot, primaryStage, n).isSameTask(task)) + .findFirst(); + if (taskCardNode.isPresent()) { + return new FloatingTaskCardHandle(guiRobot, primaryStage, taskCardNode.get()); + } else { + return null; + } + } + + protected Set getAllCardNodes() { + return guiRobot.lookup(CARD_PANE_ID).queryAll(); + } + + public int getNumberOfTasks() { + return getListView().getItems().size(); + } +} diff --git a/src/test/java/guitests/guihandles/GuiHandle.java b/src/test/java/guitests/guihandles/GuiHandle.java index 5e7e0f6de911..a64b72de370c 100644 --- a/src/test/java/guitests/guihandles/GuiHandle.java +++ b/src/test/java/guitests/guihandles/GuiHandle.java @@ -7,8 +7,8 @@ import javafx.scene.input.KeyCode; import javafx.stage.Stage; import javafx.stage.Window; -import seedu.address.TestApp; -import seedu.address.commons.core.LogsCenter; +import seedu.malitio.TestApp; +import seedu.malitio.commons.core.LogsCenter; import java.util.logging.Logger; diff --git a/src/test/java/guitests/guihandles/MainGuiHandle.java b/src/test/java/guitests/guihandles/MainGuiHandle.java index 45802c5135c7..7a48e4292481 100644 --- a/src/test/java/guitests/guihandles/MainGuiHandle.java +++ b/src/test/java/guitests/guihandles/MainGuiHandle.java @@ -2,7 +2,7 @@ import guitests.GuiRobot; import javafx.stage.Stage; -import seedu.address.TestApp; +import seedu.malitio.TestApp; /** * Provides a handle for the main GUI. @@ -13,10 +13,18 @@ public MainGuiHandle(GuiRobot guiRobot, Stage primaryStage) { super(guiRobot, primaryStage, TestApp.APP_TITLE); } - public PersonListPanelHandle getPersonListPanel() { - return new PersonListPanelHandle(guiRobot, primaryStage); + public FloatingTaskListPanelHandle getFloatingTaskListPanel() { + return new FloatingTaskListPanelHandle(guiRobot, primaryStage); } + public DeadlineListPanelHandle getDeadlineListPanel() { + return new DeadlineListPanelHandle(guiRobot, primaryStage); + } + + public EventListPanelHandle getEventListPanel() { + return new EventListPanelHandle(guiRobot, primaryStage); + } + public ResultDisplayHandle getResultDisplay() { return new ResultDisplayHandle(guiRobot, primaryStage); } diff --git a/src/test/java/guitests/guihandles/MainMenuHandle.java b/src/test/java/guitests/guihandles/MainMenuHandle.java index 0aeb047a0e1d..b2e984782667 100644 --- a/src/test/java/guitests/guihandles/MainMenuHandle.java +++ b/src/test/java/guitests/guihandles/MainMenuHandle.java @@ -3,7 +3,7 @@ import guitests.GuiRobot; import javafx.scene.input.KeyCode; import javafx.stage.Stage; -import seedu.address.TestApp; +import seedu.malitio.TestApp; import java.util.Arrays; diff --git a/src/test/java/guitests/guihandles/PersonCardHandle.java b/src/test/java/guitests/guihandles/PersonCardHandle.java deleted file mode 100644 index fae22a45ae2f..000000000000 --- a/src/test/java/guitests/guihandles/PersonCardHandle.java +++ /dev/null @@ -1,63 +0,0 @@ -package guitests.guihandles; - -import guitests.GuiRobot; -import javafx.scene.Node; -import javafx.stage.Stage; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * Provides a handle to a person card in the person list panel. - */ -public class PersonCardHandle extends GuiHandle { - private static final String NAME_FIELD_ID = "#name"; - private static final String ADDRESS_FIELD_ID = "#address"; - private static final String PHONE_FIELD_ID = "#phone"; - private static final String EMAIL_FIELD_ID = "#email"; - - private Node node; - - public PersonCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ - super(guiRobot, primaryStage, null); - this.node = node; - } - - protected String getTextFromLabel(String fieldId) { - return getTextFromLabel(fieldId, node); - } - - public String getFullName() { - return getTextFromLabel(NAME_FIELD_ID); - } - - public String getAddress() { - return getTextFromLabel(ADDRESS_FIELD_ID); - } - - public String getPhone() { - return getTextFromLabel(PHONE_FIELD_ID); - } - - public String getEmail() { - return getTextFromLabel(EMAIL_FIELD_ID); - } - - public boolean isSamePerson(ReadOnlyPerson person){ - return getFullName().equals(person.getName().fullName) && getPhone().equals(person.getPhone().value) - && getEmail().equals(person.getEmail().value) && getAddress().equals(person.getAddress().value); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof PersonCardHandle) { - PersonCardHandle handle = (PersonCardHandle) obj; - return getFullName().equals(handle.getFullName()) - && getAddress().equals(handle.getAddress()); //TODO: compare the rest - } - return super.equals(obj); - } - - @Override - public String toString() { - return getFullName() + " " + getAddress(); - } -} diff --git a/src/test/java/guitests/guihandles/PersonListPanelHandle.java b/src/test/java/guitests/guihandles/PersonListPanelHandle.java deleted file mode 100644 index 3451992cf735..000000000000 --- a/src/test/java/guitests/guihandles/PersonListPanelHandle.java +++ /dev/null @@ -1,172 +0,0 @@ -package guitests.guihandles; - - -import guitests.GuiRobot; -import javafx.geometry.Point2D; -import javafx.scene.Node; -import javafx.scene.control.ListView; -import javafx.stage.Stage; -import seedu.address.TestApp; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.testutil.TestUtil; - -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.junit.Assert.assertTrue; - -/** - * Provides a handle for the panel containing the person list. - */ -public class PersonListPanelHandle extends GuiHandle { - - public static final int NOT_FOUND = -1; - public static final String CARD_PANE_ID = "#cardPane"; - - private static final String PERSON_LIST_VIEW_ID = "#personListView"; - - public PersonListPanelHandle(GuiRobot guiRobot, Stage primaryStage) { - super(guiRobot, primaryStage, TestApp.APP_TITLE); - } - - public List getSelectedPersons() { - ListView personList = getListView(); - return personList.getSelectionModel().getSelectedItems(); - } - - public ListView getListView() { - return (ListView) getNode(PERSON_LIST_VIEW_ID); - } - - /** - * Returns true if the list is showing the person details correctly and in correct order. - * @param persons A list of person in the correct order. - */ - public boolean isListMatching(ReadOnlyPerson... persons) { - return this.isListMatching(0, persons); - } - - /** - * Clicks on the ListView. - */ - public void clickOnListView() { - Point2D point= TestUtil.getScreenMidPoint(getListView()); - guiRobot.clickOn(point.getX(), point.getY()); - } - - /** - * Returns true if the {@code persons} appear as the sub list (in that order) at position {@code startPosition}. - */ - public boolean containsInOrder(int startPosition, ReadOnlyPerson... persons) { - List personsInList = getListView().getItems(); - - // Return false if the list in panel is too short to contain the given list - if (startPosition + persons.length > personsInList.size()){ - return false; - } - - // Return false if any of the persons doesn't match - for (int i = 0; i < persons.length; i++) { - if (!personsInList.get(startPosition + i).getName().fullName.equals(persons[i].getName().fullName)){ - return false; - } - } - - return true; - } - - /** - * Returns true if the list is showing the person details correctly and in correct order. - * @param startPosition The starting position of the sub list. - * @param persons A list of person in the correct order. - */ - public boolean isListMatching(int startPosition, ReadOnlyPerson... persons) throws IllegalArgumentException { - if (persons.length + startPosition != getListView().getItems().size()) { - throw new IllegalArgumentException("List size mismatched\n" + - "Expected " + (getListView().getItems().size() - 1) + " persons"); - } - assertTrue(this.containsInOrder(startPosition, persons)); - for (int i = 0; i < persons.length; i++) { - final int scrollTo = i + startPosition; - guiRobot.interact(() -> getListView().scrollTo(scrollTo)); - guiRobot.sleep(200); - if (!TestUtil.compareCardAndPerson(getPersonCardHandle(startPosition + i), persons[i])) { - return false; - } - } - return true; - } - - - public PersonCardHandle navigateToPerson(String name) { - guiRobot.sleep(500); //Allow a bit of time for the list to be updated - final Optional person = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); - if (!person.isPresent()) { - throw new IllegalStateException("Name not found: " + name); - } - - return navigateToPerson(person.get()); - } - - /** - * Navigates the listview to display and select the person. - */ - public PersonCardHandle navigateToPerson(ReadOnlyPerson person) { - int index = getPersonIndex(person); - - guiRobot.interact(() -> { - getListView().scrollTo(index); - guiRobot.sleep(150); - getListView().getSelectionModel().select(index); - }); - guiRobot.sleep(100); - return getPersonCardHandle(person); - } - - - /** - * Returns the position of the person given, {@code NOT_FOUND} if not found in the list. - */ - public int getPersonIndex(ReadOnlyPerson targetPerson) { - List personsInList = getListView().getItems(); - for (int i = 0; i < personsInList.size(); i++) { - if(personsInList.get(i).getName().equals(targetPerson.getName())){ - return i; - } - } - return NOT_FOUND; - } - - /** - * Gets a person from the list by index - */ - public ReadOnlyPerson getPerson(int index) { - return getListView().getItems().get(index); - } - - public PersonCardHandle getPersonCardHandle(int index) { - return getPersonCardHandle(new Person(getListView().getItems().get(index))); - } - - public PersonCardHandle getPersonCardHandle(ReadOnlyPerson person) { - Set nodes = getAllCardNodes(); - Optional personCardNode = nodes.stream() - .filter(n -> new PersonCardHandle(guiRobot, primaryStage, n).isSamePerson(person)) - .findFirst(); - if (personCardNode.isPresent()) { - return new PersonCardHandle(guiRobot, primaryStage, personCardNode.get()); - } else { - return null; - } - } - - protected Set getAllCardNodes() { - return guiRobot.lookup(CARD_PANE_ID).queryAll(); - } - - public int getNumberOfPeople() { - return getListView().getItems().size(); - } -} diff --git a/src/test/java/guitests/guihandles/ResultDisplayHandle.java b/src/test/java/guitests/guihandles/ResultDisplayHandle.java index 110b4682b184..212804c078dd 100644 --- a/src/test/java/guitests/guihandles/ResultDisplayHandle.java +++ b/src/test/java/guitests/guihandles/ResultDisplayHandle.java @@ -3,7 +3,7 @@ import guitests.GuiRobot; import javafx.scene.control.TextArea; import javafx.stage.Stage; -import seedu.address.TestApp; +import seedu.malitio.TestApp; /** * A handler for the ResultDisplay of the UI diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java deleted file mode 100644 index e1ee0cfb4051..000000000000 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ /dev/null @@ -1,512 +0,0 @@ -package seedu.address.logic; - -import com.google.common.eventbus.Subscribe; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import seedu.address.commons.core.EventsCenter; -import seedu.address.logic.commands.*; -import seedu.address.commons.events.ui.JumpToListRequestEvent; -import seedu.address.commons.events.ui.ShowHelpRequestEvent; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; -import seedu.address.storage.StorageManager; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static seedu.address.commons.core.Messages.*; - -public class LogicManagerTest { - - /** - * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule - */ - @Rule - public TemporaryFolder saveFolder = new TemporaryFolder(); - - private Model model; - private Logic logic; - - //These are for checking the correctness of the events raised - private ReadOnlyAddressBook latestSavedAddressBook; - private boolean helpShown; - private int targetedJumpIndex; - - @Subscribe - private void handleLocalModelChangedEvent(AddressBookChangedEvent abce) { - latestSavedAddressBook = new AddressBook(abce.data); - } - - @Subscribe - private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) { - helpShown = true; - } - - @Subscribe - private void handleJumpToListRequestEvent(JumpToListRequestEvent je) { - targetedJumpIndex = je.targetIndex; - } - - @Before - public void setup() { - model = new ModelManager(); - String tempAddressBookFile = saveFolder.getRoot().getPath() + "TempAddressBook.xml"; - String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json"; - logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile)); - EventsCenter.getInstance().registerHandler(this); - - latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before. - helpShown = false; - targetedJumpIndex = -1; // non yet - } - - @After - public void teardown() { - EventsCenter.clearSubscribers(); - } - - @Test - public void execute_invalid() throws Exception { - String invalidCommand = " "; - assertCommandBehavior(invalidCommand, - String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); - } - - /** - * Executes the command and confirms that the result message is correct. - * Both the 'address book' and the 'last shown list' are expected to be empty. - * @see #assertCommandBehavior(String, String, ReadOnlyAddressBook, List) - */ - private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { - assertCommandBehavior(inputCommand, expectedMessage, new AddressBook(), Collections.emptyList()); - } - - /** - * Executes the command and confirms that the result message is correct and - * also confirms that the following three parts of the LogicManager object's state are as expected:
- * - the internal address book data are same as those in the {@code expectedAddressBook}
- * - the backing list shown by UI matches the {@code shownList}
- * - {@code expectedAddressBook} was saved to the storage file.
- */ - private void assertCommandBehavior(String inputCommand, String expectedMessage, - ReadOnlyAddressBook expectedAddressBook, - List expectedShownList) throws Exception { - - //Execute the command - CommandResult result = logic.execute(inputCommand); - - //Confirm the ui display elements should contain the right data - assertEquals(expectedMessage, result.feedbackToUser); - assertEquals(expectedShownList, model.getFilteredPersonList()); - - //Confirm the state of data (saved and in-memory) is as expected - assertEquals(expectedAddressBook, model.getAddressBook()); - assertEquals(expectedAddressBook, latestSavedAddressBook); - } - - - @Test - public void execute_unknownCommandWord() throws Exception { - String unknownCommand = "uicfhmowqewca"; - assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND); - } - - @Test - public void execute_help() throws Exception { - assertCommandBehavior("help", HelpCommand.SHOWING_HELP_MESSAGE); - assertTrue(helpShown); - } - - @Test - public void execute_exit() throws Exception { - assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT); - } - - @Test - public void execute_clear() throws Exception { - TestDataHelper helper = new TestDataHelper(); - model.addPerson(helper.generatePerson(1)); - model.addPerson(helper.generatePerson(2)); - model.addPerson(helper.generatePerson(3)); - - assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new AddressBook(), Collections.emptyList()); - } - - - @Test - public void execute_add_invalidArgsFormat() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); - assertCommandBehavior( - "add wrong args wrong args", expectedMessage); - assertCommandBehavior( - "add Valid Name 12345 e/valid@email.butNoPhonePrefix a/valid, address", expectedMessage); - assertCommandBehavior( - "add Valid Name p/12345 valid@email.butNoPrefix a/valid, address", expectedMessage); - assertCommandBehavior( - "add Valid Name p/12345 e/valid@email.butNoAddressPrefix valid, address", expectedMessage); - } - - @Test - public void execute_add_invalidPersonData() throws Exception { - assertCommandBehavior( - "add []\\[;] p/12345 e/valid@e.mail a/valid, address", Name.MESSAGE_NAME_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/not_numbers e/valid@e.mail a/valid, address", Phone.MESSAGE_PHONE_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/12345 e/notAnEmail a/valid, address", Email.MESSAGE_EMAIL_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/12345 e/valid@e.mail a/valid, address t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); - - } - - @Test - public void execute_add_successful() throws Exception { - // setup expectations - TestDataHelper helper = new TestDataHelper(); - Person toBeAdded = helper.adam(); - AddressBook expectedAB = new AddressBook(); - expectedAB.addPerson(toBeAdded); - - // execute command and verify result - assertCommandBehavior(helper.generateAddCommand(toBeAdded), - String.format(AddCommand.MESSAGE_SUCCESS, toBeAdded), - expectedAB, - expectedAB.getPersonList()); - - } - - @Test - public void execute_addDuplicate_notAllowed() throws Exception { - // setup expectations - TestDataHelper helper = new TestDataHelper(); - Person toBeAdded = helper.adam(); - AddressBook expectedAB = new AddressBook(); - expectedAB.addPerson(toBeAdded); - - // setup starting state - model.addPerson(toBeAdded); // person already in internal address book - - // execute command and verify result - assertCommandBehavior( - helper.generateAddCommand(toBeAdded), - AddCommand.MESSAGE_DUPLICATE_PERSON, - expectedAB, - expectedAB.getPersonList()); - - } - - - @Test - public void execute_list_showsAllPersons() throws Exception { - // prepare expectations - TestDataHelper helper = new TestDataHelper(); - AddressBook expectedAB = helper.generateAddressBook(2); - List expectedList = expectedAB.getPersonList(); - - // prepare address book state - helper.addToModel(model, 2); - - assertCommandBehavior("list", - ListCommand.MESSAGE_SUCCESS, - expectedAB, - expectedList); - } - - - /** - * Confirms the 'invalid argument index number behaviour' for the given command - * targeting a single person in the shown list, using visible index. - * @param commandWord to test assuming it targets a single person in the last shown list based on visible index. - */ - private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { - assertCommandBehavior(commandWord , expectedMessage); //index missing - assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned - assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned - assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0 - assertCommandBehavior(commandWord + " not_a_number", expectedMessage); - } - - /** - * Confirms the 'invalid argument index number behaviour' for the given command - * targeting a single person in the shown list, using visible index. - * @param commandWord to test assuming it targets a single person in the last shown list based on visible index. - */ - private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { - String expectedMessage = MESSAGE_INVALID_PERSON_DISPLAYED_INDEX; - TestDataHelper helper = new TestDataHelper(); - List personList = helper.generatePersonList(2); - - // set AB state to 2 persons - model.resetData(new AddressBook()); - for (Person p : personList) { - model.addPerson(p); - } - - assertCommandBehavior(commandWord + " 3", expectedMessage, model.getAddressBook(), personList); - } - - @Test - public void execute_selectInvalidArgsFormat_errorMessageShown() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE); - assertIncorrectIndexFormatBehaviorForCommand("select", expectedMessage); - } - - @Test - public void execute_selectIndexNotFound_errorMessageShown() throws Exception { - assertIndexNotFoundBehaviorForCommand("select"); - } - - @Test - public void execute_select_jumpsToCorrectPerson() throws Exception { - TestDataHelper helper = new TestDataHelper(); - List threePersons = helper.generatePersonList(3); - - AddressBook expectedAB = helper.generateAddressBook(threePersons); - helper.addToModel(model, threePersons); - - assertCommandBehavior("select 2", - String.format(SelectCommand.MESSAGE_SELECT_PERSON_SUCCESS, 2), - expectedAB, - expectedAB.getPersonList()); - assertEquals(1, targetedJumpIndex); - assertEquals(model.getFilteredPersonList().get(1), threePersons.get(1)); - } - - - @Test - public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE); - assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage); - } - - @Test - public void execute_deleteIndexNotFound_errorMessageShown() throws Exception { - assertIndexNotFoundBehaviorForCommand("delete"); - } - - @Test - public void execute_delete_removesCorrectPerson() throws Exception { - TestDataHelper helper = new TestDataHelper(); - List threePersons = helper.generatePersonList(3); - - AddressBook expectedAB = helper.generateAddressBook(threePersons); - expectedAB.removePerson(threePersons.get(1)); - helper.addToModel(model, threePersons); - - assertCommandBehavior("delete 2", - String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, threePersons.get(1)), - expectedAB, - expectedAB.getPersonList()); - } - - - @Test - public void execute_find_invalidArgsFormat() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); - assertCommandBehavior("find ", expectedMessage); - } - - @Test - public void execute_find_onlyMatchesFullWordsInNames() throws Exception { - TestDataHelper helper = new TestDataHelper(); - Person pTarget1 = helper.generatePersonWithName("bla bla KEY bla"); - Person pTarget2 = helper.generatePersonWithName("bla KEY bla bceofeia"); - Person p1 = helper.generatePersonWithName("KE Y"); - Person p2 = helper.generatePersonWithName("KEYKEYKEY sduauo"); - - List fourPersons = helper.generatePersonList(p1, pTarget1, p2, pTarget2); - AddressBook expectedAB = helper.generateAddressBook(fourPersons); - List expectedList = helper.generatePersonList(pTarget1, pTarget2); - helper.addToModel(model, fourPersons); - - assertCommandBehavior("find KEY", - Command.getMessageForPersonListShownSummary(expectedList.size()), - expectedAB, - expectedList); - } - - @Test - public void execute_find_isNotCaseSensitive() throws Exception { - TestDataHelper helper = new TestDataHelper(); - Person p1 = helper.generatePersonWithName("bla bla KEY bla"); - Person p2 = helper.generatePersonWithName("bla KEY bla bceofeia"); - Person p3 = helper.generatePersonWithName("key key"); - Person p4 = helper.generatePersonWithName("KEy sduauo"); - - List fourPersons = helper.generatePersonList(p3, p1, p4, p2); - AddressBook expectedAB = helper.generateAddressBook(fourPersons); - List expectedList = fourPersons; - helper.addToModel(model, fourPersons); - - assertCommandBehavior("find KEY", - Command.getMessageForPersonListShownSummary(expectedList.size()), - expectedAB, - expectedList); - } - - @Test - public void execute_find_matchesIfAnyKeywordPresent() throws Exception { - TestDataHelper helper = new TestDataHelper(); - Person pTarget1 = helper.generatePersonWithName("bla bla KEY bla"); - Person pTarget2 = helper.generatePersonWithName("bla rAnDoM bla bceofeia"); - Person pTarget3 = helper.generatePersonWithName("key key"); - Person p1 = helper.generatePersonWithName("sduauo"); - - List fourPersons = helper.generatePersonList(pTarget1, p1, pTarget2, pTarget3); - AddressBook expectedAB = helper.generateAddressBook(fourPersons); - List expectedList = helper.generatePersonList(pTarget1, pTarget2, pTarget3); - helper.addToModel(model, fourPersons); - - assertCommandBehavior("find key rAnDoM", - Command.getMessageForPersonListShownSummary(expectedList.size()), - expectedAB, - expectedList); - } - - - /** - * A utility class to generate test data. - */ - class TestDataHelper{ - - Person adam() throws Exception { - Name name = new Name("Adam Brown"); - Phone privatePhone = new Phone("111111"); - Email email = new Email("adam@gmail.com"); - Address privateAddress = new Address("111, alpha street"); - Tag tag1 = new Tag("tag1"); - Tag tag2 = new Tag("tag2"); - UniqueTagList tags = new UniqueTagList(tag1, tag2); - return new Person(name, privatePhone, email, privateAddress, tags); - } - - /** - * Generates a valid person using the given seed. - * Running this function with the same parameter values guarantees the returned person will have the same state. - * Each unique seed will generate a unique Person object. - * - * @param seed used to generate the person data field values - */ - Person generatePerson(int seed) throws Exception { - return new Person( - new Name("Person " + seed), - new Phone("" + Math.abs(seed)), - new Email(seed + "@email"), - new Address("House of " + seed), - new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1))) - ); - } - - /** Generates the correct add command based on the person given */ - String generateAddCommand(Person p) { - StringBuffer cmd = new StringBuffer(); - - cmd.append("add "); - - cmd.append(p.getName().toString()); - cmd.append(" p/").append(p.getPhone()); - cmd.append(" e/").append(p.getEmail()); - cmd.append(" a/").append(p.getAddress()); - - UniqueTagList tags = p.getTags(); - for(Tag t: tags){ - cmd.append(" t/").append(t.tagName); - } - - return cmd.toString(); - } - - /** - * Generates an AddressBook with auto-generated persons. - */ - AddressBook generateAddressBook(int numGenerated) throws Exception{ - AddressBook addressBook = new AddressBook(); - addToAddressBook(addressBook, numGenerated); - return addressBook; - } - - /** - * Generates an AddressBook based on the list of Persons given. - */ - AddressBook generateAddressBook(List persons) throws Exception{ - AddressBook addressBook = new AddressBook(); - addToAddressBook(addressBook, persons); - return addressBook; - } - - /** - * Adds auto-generated Person objects to the given AddressBook - * @param addressBook The AddressBook to which the Persons will be added - */ - void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{ - addToAddressBook(addressBook, generatePersonList(numGenerated)); - } - - /** - * Adds the given list of Persons to the given AddressBook - */ - void addToAddressBook(AddressBook addressBook, List personsToAdd) throws Exception{ - for(Person p: personsToAdd){ - addressBook.addPerson(p); - } - } - - /** - * Adds auto-generated Person objects to the given model - * @param model The model to which the Persons will be added - */ - void addToModel(Model model, int numGenerated) throws Exception{ - addToModel(model, generatePersonList(numGenerated)); - } - - /** - * Adds the given list of Persons to the given model - */ - void addToModel(Model model, List personsToAdd) throws Exception{ - for(Person p: personsToAdd){ - model.addPerson(p); - } - } - - /** - * Generates a list of Persons based on the flags. - */ - List generatePersonList(int numGenerated) throws Exception{ - List persons = new ArrayList<>(); - for(int i = 1; i <= numGenerated; i++){ - persons.add(generatePerson(i)); - } - return persons; - } - - List generatePersonList(Person... persons) { - return Arrays.asList(persons); - } - - /** - * Generates a Person object with given name. Other fields will have some dummy values. - */ - Person generatePersonWithName(String name) throws Exception { - return new Person( - new Name(name), - new Phone("1"), - new Email("1@email"), - new Address("House of 1"), - new UniqueTagList(new Tag("tag")) - ); - } - } -} diff --git a/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java b/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java deleted file mode 100644 index 04b0db1ce1c7..000000000000 --- a/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package seedu.address.storage; - - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; -import seedu.address.testutil.TypicalTestPersons; - -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -public class XmlAddressBookStorageTest { - private static String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/XmlAddressBookStorageTest/"); - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Rule - public TemporaryFolder testFolder = new TemporaryFolder(); - - @Test - public void readAddressBook_nullFilePath_assertionFailure() throws Exception { - thrown.expect(AssertionError.class); - readAddressBook(null); - } - - private java.util.Optional readAddressBook(String filePath) throws Exception { - return new XmlAddressBookStorage(filePath).readAddressBook(addToTestDataPathIfNotNull(filePath)); - } - - private String addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) { - return prefsFileInTestDataFolder != null - ? TEST_DATA_FOLDER + prefsFileInTestDataFolder - : null; - } - - @Test - public void read_missingFile_emptyResult() throws Exception { - assertFalse(readAddressBook("NonExistentFile.xml").isPresent()); - } - - @Test - public void read_notXmlFormat_exceptionThrown() throws Exception { - - thrown.expect(DataConversionException.class); - readAddressBook("NotXmlFormatAddressBook.xml"); - - /* IMPORTANT: Any code below an exception-throwing line (like the one above) will be ignored. - * That means you should not have more than one exception test in one method - */ - } - - @Test - public void readAndSaveAddressBook_allInOrder_success() throws Exception { - String filePath = testFolder.getRoot().getPath() + "TempAddressBook.xml"; - TypicalTestPersons td = new TypicalTestPersons(); - AddressBook original = td.getTypicalAddressBook(); - XmlAddressBookStorage xmlAddressBookStorage = new XmlAddressBookStorage(filePath); - - //Save in new file and read back - xmlAddressBookStorage.saveAddressBook(original, filePath); - ReadOnlyAddressBook readBack = xmlAddressBookStorage.readAddressBook(filePath).get(); - assertEquals(original, new AddressBook(readBack)); - - //Modify data, overwrite exiting file, and read back - original.addPerson(new Person(TypicalTestPersons.hoon)); - original.removePerson(new Person(TypicalTestPersons.alice)); - xmlAddressBookStorage.saveAddressBook(original, filePath); - readBack = xmlAddressBookStorage.readAddressBook(filePath).get(); - assertEquals(original, new AddressBook(readBack)); - - //Save and read without specifying file path - original.addPerson(new Person(TypicalTestPersons.ida)); - xmlAddressBookStorage.saveAddressBook(original); //file path not specified - readBack = xmlAddressBookStorage.readAddressBook().get(); //file path not specified - assertEquals(original, new AddressBook(readBack)); - - } - - @Test - public void saveAddressBook_nullAddressBook_assertionFailure() throws IOException { - thrown.expect(AssertionError.class); - saveAddressBook(null, "SomeFile.xml"); - } - - private void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) throws IOException { - new XmlAddressBookStorage(filePath).saveAddressBook(addressBook, addToTestDataPathIfNotNull(filePath)); - } - - @Test - public void saveAddressBook_nullFilePath_assertionFailure() throws IOException { - thrown.expect(AssertionError.class); - saveAddressBook(new AddressBook(), null); - } - - -} diff --git a/src/test/java/seedu/address/testutil/AddressBookBuilder.java b/src/test/java/seedu/address/testutil/AddressBookBuilder.java deleted file mode 100644 index a623b81c878f..000000000000 --- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java +++ /dev/null @@ -1,35 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; -import seedu.address.model.AddressBook; -import seedu.address.model.person.Person; -import seedu.address.model.person.UniquePersonList; - -/** - * A utility class to help with building Addressbook objects. - * Example usage:
- * {@code AddressBook ab = new AddressBookBuilder().withPerson("John", "Doe").withTag("Friend").build();} - */ -public class AddressBookBuilder { - - private AddressBook addressBook; - - public AddressBookBuilder(AddressBook addressBook){ - this.addressBook = addressBook; - } - - public AddressBookBuilder withPerson(Person person) throws UniquePersonList.DuplicatePersonException { - addressBook.addPerson(person); - return this; - } - - public AddressBookBuilder withTag(String tagName) throws IllegalValueException { - addressBook.addTag(new Tag(tagName)); - return this; - } - - public AddressBook build(){ - return addressBook; - } -} diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java deleted file mode 100644 index 8b02a1668ef6..000000000000 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; -import seedu.address.model.person.*; - -/** - * - */ -public class PersonBuilder { - - private TestPerson person; - - public PersonBuilder() { - this.person = new TestPerson(); - } - - public PersonBuilder withName(String name) throws IllegalValueException { - this.person.setName(new Name(name)); - return this; - } - - public PersonBuilder withTags(String ... tags) throws IllegalValueException { - for (String tag: tags) { - person.getTags().add(new Tag(tag)); - } - return this; - } - - public PersonBuilder withAddress(String address) throws IllegalValueException { - this.person.setAddress(new Address(address)); - return this; - } - - public PersonBuilder withPhone(String phone) throws IllegalValueException { - this.person.setPhone(new Phone(phone)); - return this; - } - - public PersonBuilder withEmail(String email) throws IllegalValueException { - this.person.setEmail(new Email(email)); - return this; - } - - public TestPerson build() { - return this.person; - } - -} diff --git a/src/test/java/seedu/address/testutil/TestPerson.java b/src/test/java/seedu/address/testutil/TestPerson.java deleted file mode 100644 index 19ee5ded1cd3..000000000000 --- a/src/test/java/seedu/address/testutil/TestPerson.java +++ /dev/null @@ -1,76 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.model.tag.UniqueTagList; -import seedu.address.model.person.*; - -/** - * A mutable person object. For testing only. - */ -public class TestPerson implements ReadOnlyPerson { - - private Name name; - private Address address; - private Email email; - private Phone phone; - private UniqueTagList tags; - - public TestPerson() { - tags = new UniqueTagList(); - } - - public void setName(Name name) { - this.name = name; - } - - public void setAddress(Address address) { - this.address = address; - } - - public void setEmail(Email email) { - this.email = email; - } - - public void setPhone(Phone phone) { - this.phone = phone; - } - - @Override - public Name getName() { - return name; - } - - @Override - public Phone getPhone() { - return phone; - } - - @Override - public Email getEmail() { - return email; - } - - @Override - public Address getAddress() { - return address; - } - - @Override - public UniqueTagList getTags() { - return tags; - } - - @Override - public String toString() { - return getAsText(); - } - - public String getAddCommand() { - StringBuilder sb = new StringBuilder(); - sb.append("add " + this.getName().fullName + " "); - sb.append("p/" + this.getPhone().value + " "); - sb.append("e/" + this.getEmail().value + " "); - sb.append("a/" + this.getAddress().value + " "); - this.getTags().getInternalList().stream().forEach(s -> sb.append("t/" + s.tagName + " ")); - return sb.toString(); - } -} diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/address/testutil/TestUtil.java deleted file mode 100644 index 17c92d66398a..000000000000 --- a/src/test/java/seedu/address/testutil/TestUtil.java +++ /dev/null @@ -1,354 +0,0 @@ -package seedu.address.testutil; - -import com.google.common.io.Files; -import guitests.guihandles.PersonCardHandle; -import javafx.geometry.Bounds; -import javafx.geometry.Point2D; -import javafx.scene.Node; -import javafx.scene.Scene; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyCodeCombination; -import javafx.scene.input.KeyCombination; -import junit.framework.AssertionFailedError; -import org.loadui.testfx.GuiTest; -import org.testfx.api.FxToolkit; -import seedu.address.TestApp; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.commons.util.FileUtil; -import seedu.address.commons.util.XmlUtil; -import seedu.address.model.AddressBook; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; -import seedu.address.storage.XmlSerializableAddressBook; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; - -/** - * A utility class for test cases. - */ -public class TestUtil { - - public static String LS = System.lineSeparator(); - - public static void assertThrows(Class expected, Runnable executable) { - try { - executable.run(); - } - catch (Throwable actualException) { - if (!actualException.getClass().isAssignableFrom(expected)) { - String message = String.format("Expected thrown: %s, actual: %s", expected.getName(), - actualException.getClass().getName()); - throw new AssertionFailedError(message); - } else return; - } - throw new AssertionFailedError( - String.format("Expected %s to be thrown, but nothing was thrown.", expected.getName())); - } - - /** - * Folder used for temp files created during testing. Ignored by Git. - */ - public static String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); - - public static final Person[] samplePersonData = getSamplePersonData(); - - private static Person[] getSamplePersonData() { - try { - return new Person[]{ - new Person(new Name("Ali Muster"), new Phone("9482424"), new Email("hans@google.com"), new Address("4th street"), new UniqueTagList()), - new Person(new Name("Boris Mueller"), new Phone("87249245"), new Email("ruth@google.com"), new Address("81th street"), new UniqueTagList()), - new Person(new Name("Carl Kurz"), new Phone("95352563"), new Email("heinz@yahoo.com"), new Address("wall street"), new UniqueTagList()), - new Person(new Name("Daniel Meier"), new Phone("87652533"), new Email("cornelia@google.com"), new Address("10th street"), new UniqueTagList()), - new Person(new Name("Elle Meyer"), new Phone("9482224"), new Email("werner@gmail.com"), new Address("michegan ave"), new UniqueTagList()), - new Person(new Name("Fiona Kunz"), new Phone("9482427"), new Email("lydia@gmail.com"), new Address("little tokyo"), new UniqueTagList()), - new Person(new Name("George Best"), new Phone("9482442"), new Email("anna@google.com"), new Address("4th street"), new UniqueTagList()), - new Person(new Name("Hoon Meier"), new Phone("8482424"), new Email("stefan@mail.com"), new Address("little india"), new UniqueTagList()), - new Person(new Name("Ida Mueller"), new Phone("8482131"), new Email("hans@google.com"), new Address("chicago ave"), new UniqueTagList()) - }; - } catch (IllegalValueException e) { - assert false; - //not possible - return null; - } - } - - public static final Tag[] sampleTagData = getSampleTagData(); - - private static Tag[] getSampleTagData() { - try { - return new Tag[]{ - new Tag("relatives"), - new Tag("friends") - }; - } catch (IllegalValueException e) { - assert false; - return null; - //not possible - } - } - - public static List generateSamplePersonData() { - return Arrays.asList(samplePersonData); - } - - /** - * Appends the file name to the sandbox folder path. - * Creates the sandbox folder if it doesn't exist. - * @param fileName - * @return - */ - public static String getFilePathInSandboxFolder(String fileName) { - try { - FileUtil.createDirs(new File(SANDBOX_FOLDER)); - } catch (IOException e) { - throw new RuntimeException(e); - } - return SANDBOX_FOLDER + fileName; - } - - public static void createDataFileWithSampleData(String filePath) { - createDataFileWithData(generateSampleStorageAddressBook(), filePath); - } - - public static void createDataFileWithData(T data, String filePath) { - try { - File saveFileForTesting = new File(filePath); - FileUtil.createIfMissing(saveFileForTesting); - XmlUtil.saveDataToFile(saveFileForTesting, data); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static void main(String... s) { - createDataFileWithSampleData(TestApp.SAVE_LOCATION_FOR_TESTING); - } - - public static AddressBook generateEmptyAddressBook() { - return new AddressBook(new UniquePersonList(), new UniqueTagList()); - } - - public static XmlSerializableAddressBook generateSampleStorageAddressBook() { - return new XmlSerializableAddressBook(generateEmptyAddressBook()); - } - - /** - * Tweaks the {@code keyCodeCombination} to resolve the {@code KeyCode.SHORTCUT} to their - * respective platform-specific keycodes - */ - public static KeyCode[] scrub(KeyCodeCombination keyCodeCombination) { - List keys = new ArrayList<>(); - if (keyCodeCombination.getAlt() == KeyCombination.ModifierValue.DOWN) { - keys.add(KeyCode.ALT); - } - if (keyCodeCombination.getShift() == KeyCombination.ModifierValue.DOWN) { - keys.add(KeyCode.SHIFT); - } - if (keyCodeCombination.getMeta() == KeyCombination.ModifierValue.DOWN) { - keys.add(KeyCode.META); - } - if (keyCodeCombination.getControl() == KeyCombination.ModifierValue.DOWN) { - keys.add(KeyCode.CONTROL); - } - keys.add(keyCodeCombination.getCode()); - return keys.toArray(new KeyCode[]{}); - } - - public static boolean isHeadlessEnvironment() { - String headlessProperty = System.getProperty("testfx.headless"); - return headlessProperty != null && headlessProperty.equals("true"); - } - - public static void captureScreenShot(String fileName) { - File file = GuiTest.captureScreenshot(); - try { - Files.copy(file, new File(fileName + ".png")); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static String descOnFail(Object... comparedObjects) { - return "Comparison failed \n" - + Arrays.asList(comparedObjects).stream() - .map(Object::toString) - .collect(Collectors.joining("\n")); - } - - public static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException{ - field.setAccessible(true); - // remove final modifier from field - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - // ~Modifier.FINAL is used to remove the final modifier from field so that its value is no longer - // final and can be changed - modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); - field.set(null, newValue); - } - - public static void initRuntime() throws TimeoutException { - FxToolkit.registerPrimaryStage(); - FxToolkit.hideStage(); - } - - public static void tearDownRuntime() throws Exception { - FxToolkit.cleanupStages(); - } - - /** - * Gets private method of a class - * Invoke the method using method.invoke(objectInstance, params...) - * - * Caveat: only find method declared in the current Class, not inherited from supertypes - */ - public static Method getPrivateMethod(Class objectClass, String methodName) throws NoSuchMethodException { - Method method = objectClass.getDeclaredMethod(methodName); - method.setAccessible(true); - return method; - } - - public static void renameFile(File file, String newFileName) { - try { - Files.copy(file, new File(newFileName)); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - - /** - * Gets mid point of a node relative to the screen. - * @param node - * @return - */ - public static Point2D getScreenMidPoint(Node node) { - double x = getScreenPos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; - double y = getScreenPos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; - return new Point2D(x,y); - } - - /** - * Gets mid point of a node relative to its scene. - * @param node - * @return - */ - public static Point2D getSceneMidPoint(Node node) { - double x = getScenePos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; - double y = getScenePos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; - return new Point2D(x,y); - } - - /** - * Gets the bound of the node relative to the parent scene. - * @param node - * @return - */ - public static Bounds getScenePos(Node node) { - return node.localToScene(node.getBoundsInLocal()); - } - - public static Bounds getScreenPos(Node node) { - return node.localToScreen(node.getBoundsInLocal()); - } - - public static double getSceneMaxX(Scene scene) { - return scene.getX() + scene.getWidth(); - } - - public static double getSceneMaxY(Scene scene) { - return scene.getX() + scene.getHeight(); - } - - public static Object getLastElement(List list) { - return list.get(list.size() - 1); - } - - /** - * Removes a subset from the list of persons. - * @param persons The list of persons - * @param personsToRemove The subset of persons. - * @return The modified persons after removal of the subset from persons. - */ - public static TestPerson[] removePersonsFromList(final TestPerson[] persons, TestPerson... personsToRemove) { - List listOfPersons = asList(persons); - listOfPersons.removeAll(asList(personsToRemove)); - return listOfPersons.toArray(new TestPerson[listOfPersons.size()]); - } - - - /** - * Returns a copy of the list with the person at specified index removed. - * @param list original list to copy from - * @param targetIndexInOneIndexedFormat e.g. if the first element to be removed, 1 should be given as index. - */ - public static TestPerson[] removePersonFromList(final TestPerson[] list, int targetIndexInOneIndexedFormat) { - return removePersonsFromList(list, list[targetIndexInOneIndexedFormat-1]); - } - - /** - * Replaces persons[i] with a person. - * @param persons The array of persons. - * @param person The replacement person - * @param index The index of the person to be replaced. - * @return - */ - public static TestPerson[] replacePersonFromList(TestPerson[] persons, TestPerson person, int index) { - persons[index] = person; - return persons; - } - - /** - * Appends persons to the array of persons. - * @param persons A array of persons. - * @param personsToAdd The persons that are to be appended behind the original array. - * @return The modified array of persons. - */ - public static TestPerson[] addPersonsToList(final TestPerson[] persons, TestPerson... personsToAdd) { - List listOfPersons = asList(persons); - listOfPersons.addAll(asList(personsToAdd)); - return listOfPersons.toArray(new TestPerson[listOfPersons.size()]); - } - - private static List asList(T[] objs) { - List list = new ArrayList<>(); - for(T obj : objs) { - list.add(obj); - } - return list; - } - - public static boolean compareCardAndPerson(PersonCardHandle card, ReadOnlyPerson person) { - return card.isSamePerson(person); - } - - public static Tag[] getTagList(String tags) { - - if (tags.equals("")) { - return new Tag[]{}; - } - - final String[] split = tags.split(", "); - - final List collect = Arrays.asList(split).stream().map(e -> { - try { - return new Tag(e.replaceFirst("Tag: ", "")); - } catch (IllegalValueException e1) { - //not possible - assert false; - return null; - } - }).collect(Collectors.toList()); - - return collect.toArray(new Tag[split.length]); - } - -} diff --git a/src/test/java/seedu/address/testutil/TypicalTestPersons.java b/src/test/java/seedu/address/testutil/TypicalTestPersons.java deleted file mode 100644 index 773f64a98cc3..000000000000 --- a/src/test/java/seedu/address/testutil/TypicalTestPersons.java +++ /dev/null @@ -1,61 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.AddressBook; -import seedu.address.model.person.*; - -/** - * - */ -public class TypicalTestPersons { - - public static TestPerson alice, benson, carl, daniel, elle, fiona, george, hoon, ida; - - public TypicalTestPersons() { - try { - alice = new PersonBuilder().withName("Alice Pauline").withAddress("123, Jurong West Ave 6, #08-111") - .withEmail("alice@gmail.com").withPhone("85355255") - .withTags("friends").build(); - benson = new PersonBuilder().withName("Benson Meier").withAddress("311, Clementi Ave 2, #02-25") - .withEmail("johnd@gmail.com").withPhone("98765432") - .withTags("owesMoney", "friends").build(); - carl = new PersonBuilder().withName("Carl Kurz").withPhone("95352563").withEmail("heinz@yahoo.com").withAddress("wall street").build(); - daniel = new PersonBuilder().withName("Daniel Meier").withPhone("87652533").withEmail("cornelia@google.com").withAddress("10th street").build(); - elle = new PersonBuilder().withName("Elle Meyer").withPhone("9482224").withEmail("werner@gmail.com").withAddress("michegan ave").build(); - fiona = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427").withEmail("lydia@gmail.com").withAddress("little tokyo").build(); - george = new PersonBuilder().withName("George Best").withPhone("9482442").withEmail("anna@google.com").withAddress("4th street").build(); - - //Manually added - hoon = new PersonBuilder().withName("Hoon Meier").withPhone("8482424").withEmail("stefan@mail.com").withAddress("little india").build(); - ida = new PersonBuilder().withName("Ida Mueller").withPhone("8482131").withEmail("hans@google.com").withAddress("chicago ave").build(); - } catch (IllegalValueException e) { - e.printStackTrace(); - assert false : "not possible"; - } - } - - public static void loadAddressBookWithSampleData(AddressBook ab) { - - try { - ab.addPerson(new Person(alice)); - ab.addPerson(new Person(benson)); - ab.addPerson(new Person(carl)); - ab.addPerson(new Person(daniel)); - ab.addPerson(new Person(elle)); - ab.addPerson(new Person(fiona)); - ab.addPerson(new Person(george)); - } catch (UniquePersonList.DuplicatePersonException e) { - assert false : "not possible"; - } - } - - public TestPerson[] getTypicalPersons() { - return new TestPerson[]{alice, benson, carl, daniel, elle, fiona, george}; - } - - public AddressBook getTypicalAddressBook(){ - AddressBook ab = new AddressBook(); - loadAddressBookWithSampleData(ab); - return ab; - } -} diff --git a/src/test/java/seedu/address/TestApp.java b/src/test/java/seedu/malitio/TestApp.java similarity index 67% rename from src/test/java/seedu/address/TestApp.java rename to src/test/java/seedu/malitio/TestApp.java index 756642b6c180..dbc8939c1911 100644 --- a/src/test/java/seedu/address/TestApp.java +++ b/src/test/java/seedu/malitio/TestApp.java @@ -1,13 +1,14 @@ -package seedu.address; +package seedu.malitio; import javafx.stage.Screen; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.GuiSettings; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; -import seedu.address.storage.XmlSerializableAddressBook; -import seedu.address.testutil.TestUtil; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.MainApp; +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.core.GuiSettings; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.UserPrefs; +import seedu.malitio.storage.XmlSerializableMalitio; import java.util.function.Supplier; @@ -20,14 +21,14 @@ public class TestApp extends MainApp { public static final String SAVE_LOCATION_FOR_TESTING = TestUtil.getFilePathInSandboxFolder("sampleData.xml"); protected static final String DEFAULT_PREF_FILE_LOCATION_FOR_TESTING = TestUtil.getFilePathInSandboxFolder("pref_testing.json"); public static final String APP_TITLE = "Test App"; - protected static final String ADDRESS_BOOK_NAME = "Test"; - protected Supplier initialDataSupplier = () -> null; + protected static final String MALITIO_NAME = "Test"; + protected Supplier initialDataSupplier = () -> null; protected String saveFileLocation = SAVE_LOCATION_FOR_TESTING; public TestApp() { } - public TestApp(Supplier initialDataSupplier, String saveFileLocation) { + public TestApp(Supplier initialDataSupplier, String saveFileLocation) { super(); this.initialDataSupplier = initialDataSupplier; this.saveFileLocation = saveFileLocation; @@ -35,7 +36,7 @@ public TestApp(Supplier initialDataSupplier, String saveFil // If some initial local data has been provided, write those to the file if (initialDataSupplier.get() != null) { TestUtil.createDataFileWithData( - new XmlSerializableAddressBook(this.initialDataSupplier.get()), + new XmlSerializableMalitio(this.initialDataSupplier.get()), this.saveFileLocation); } } @@ -44,9 +45,9 @@ public TestApp(Supplier initialDataSupplier, String saveFil protected Config initConfig(String configFilePath) { Config config = super.initConfig(configFilePath); config.setAppTitle(APP_TITLE); - config.setAddressBookFilePath(saveFileLocation); + config.setMalitioFilePath(saveFileLocation); config.setUserPrefsFilePath(DEFAULT_PREF_FILE_LOCATION_FOR_TESTING); - config.setAddressBookName(ADDRESS_BOOK_NAME); + config.setMalitioName(MALITIO_NAME); return config; } @@ -55,7 +56,7 @@ protected UserPrefs initPrefs(Config config) { UserPrefs userPrefs = super.initPrefs(config); double x = Screen.getPrimary().getVisualBounds().getMinX(); double y = Screen.getPrimary().getVisualBounds().getMinY(); - userPrefs.updateLastUsedGuiSetting(new GuiSettings(600.0, 600.0, (int) x, (int) y)); + userPrefs.updateLastUsedGuiSetting(new GuiSettings(1200.0, 600.0, (int) x, (int) y)); return userPrefs; } diff --git a/src/test/java/seedu/address/commons/core/ConfigTest.java b/src/test/java/seedu/malitio/commons/core/ConfigTest.java similarity index 75% rename from src/test/java/seedu/address/commons/core/ConfigTest.java rename to src/test/java/seedu/malitio/commons/core/ConfigTest.java index 62d58646f736..8765ed121ab1 100644 --- a/src/test/java/seedu/address/commons/core/ConfigTest.java +++ b/src/test/java/seedu/malitio/commons/core/ConfigTest.java @@ -1,9 +1,11 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.malitio.commons.core.Config; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -14,11 +16,11 @@ public class ConfigTest { @Test public void toString_defaultObject_stringReturned() { - String defaultConfigAsString = "App title : Address App\n" + + String defaultConfigAsString = "App title : Malitio\n" + "Current log level : INFO\n" + "Preference file Location : preferences.json\n" + - "Local data file location : data/addressbook.xml\n" + - "AddressBook name : MyAddressBook"; + "Local data file location : data/malitio.xml\n" + + "Malitio name : MyMalitio"; assertEquals(defaultConfigAsString, new Config().toString()); } diff --git a/src/test/java/seedu/address/commons/core/VersionTest.java b/src/test/java/seedu/malitio/commons/core/VersionTest.java similarity index 98% rename from src/test/java/seedu/address/commons/core/VersionTest.java rename to src/test/java/seedu/malitio/commons/core/VersionTest.java index 87ac01f6c92d..1b44f804be6e 100644 --- a/src/test/java/seedu/address/commons/core/VersionTest.java +++ b/src/test/java/seedu/malitio/commons/core/VersionTest.java @@ -1,9 +1,11 @@ -package seedu.address.commons.core; +package seedu.malitio.commons.core; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.malitio.commons.core.Version; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/src/test/java/seedu/address/commons/util/AppUtilTest.java b/src/test/java/seedu/malitio/commons/util/AppUtilTest.java similarity index 86% rename from src/test/java/seedu/address/commons/util/AppUtilTest.java rename to src/test/java/seedu/malitio/commons/util/AppUtilTest.java index fbea1d0c1e8e..0c4e53cc2f3e 100644 --- a/src/test/java/seedu/address/commons/util/AppUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/AppUtilTest.java @@ -1,9 +1,11 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.malitio.commons.util.AppUtil; + import static org.junit.Assert.assertNotNull; public class AppUtilTest { diff --git a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java b/src/test/java/seedu/malitio/commons/util/ConfigUtilTest.java similarity index 92% rename from src/test/java/seedu/address/commons/util/ConfigUtilTest.java rename to src/test/java/seedu/malitio/commons/util/ConfigUtilTest.java index 6699343c4a82..ca112b7844ca 100644 --- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/ConfigUtilTest.java @@ -1,12 +1,15 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.core.Config; -import seedu.address.commons.exceptions.DataConversionException; + +import seedu.malitio.commons.core.Config; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.ConfigUtil; +import seedu.malitio.commons.util.FileUtil; import java.io.File; import java.io.IOException; @@ -76,8 +79,8 @@ private Config getTypicalConfig() { config.setAppTitle("Typical App Title"); config.setLogLevel(Level.INFO); config.setUserPrefsFilePath("C:\\preferences.json"); - config.setAddressBookFilePath("addressbook.xml"); - config.setAddressBookName("TypicalAddressBookName"); + config.setMalitioFilePath("malitio.xml"); + config.setMalitioName("TypicalmalitioName"); return config; } diff --git a/src/test/java/seedu/address/commons/util/FileUtilTest.java b/src/test/java/seedu/malitio/commons/util/FileUtilTest.java similarity index 78% rename from src/test/java/seedu/address/commons/util/FileUtilTest.java rename to src/test/java/seedu/malitio/commons/util/FileUtilTest.java index 8de2621799cf..427fdd4e9f4e 100644 --- a/src/test/java/seedu/address/commons/util/FileUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/FileUtilTest.java @@ -1,16 +1,19 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.testutil.SerializableTestClass; -import seedu.address.testutil.TestUtil; +import seedu.malitio.testutil.SerializableTestClass; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.commons.util.FileUtil; import java.io.File; import java.io.IOException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class FileUtilTest { private static final File SERIALIZATION_FILE = new File(TestUtil.getFilePathInSandboxFolder("serialize.json")); @@ -55,4 +58,11 @@ public void deserializeObjectFromJsonFile_noExceptionThrown() throws IOException assertEquals(serializableTestClass.getListOfLocalDateTimes(), SerializableTestClass.getListTestValues()); assertEquals(serializableTestClass.getMapOfIntegerToString(), SerializableTestClass.getHashMapTestValues()); } + + //@@author a0126633j + @Test + public void twoFilePathsAreEqual() throws IOException { + assertTrue(FileUtil.twoFilePathsAreEqual("./data/test/", "data/../data/test/")); + assertFalse(FileUtil.twoFilePathsAreEqual("./data/tests/", "data/")); + } } diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/seedu/malitio/commons/util/JsonUtilTest.java similarity index 85% rename from src/test/java/seedu/address/commons/util/JsonUtilTest.java rename to src/test/java/seedu/malitio/commons/util/JsonUtilTest.java index fc3902188807..ee1162b4289c 100644 --- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/JsonUtilTest.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; /** * Tests JSON Read and Write diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/malitio/commons/util/StringUtilTest.java similarity index 95% rename from src/test/java/seedu/address/commons/util/StringUtilTest.java rename to src/test/java/seedu/malitio/commons/util/StringUtilTest.java index 194dd71d2c3f..4520729f1092 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/StringUtilTest.java @@ -1,9 +1,11 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.malitio.commons.util.StringUtil; + import java.io.FileNotFoundException; import static org.hamcrest.CoreMatchers.containsString; diff --git a/src/test/java/seedu/address/commons/util/UrlUtilTest.java b/src/test/java/seedu/malitio/commons/util/UrlUtilTest.java similarity index 95% rename from src/test/java/seedu/address/commons/util/UrlUtilTest.java rename to src/test/java/seedu/malitio/commons/util/UrlUtilTest.java index 58efab5fd499..eeb40501345d 100644 --- a/src/test/java/seedu/address/commons/util/UrlUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/UrlUtilTest.java @@ -1,7 +1,9 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import org.junit.Test; +import seedu.malitio.commons.util.UrlUtil; + import java.net.MalformedURLException; import java.net.URL; diff --git a/src/test/java/seedu/address/commons/util/XmlUtilTest.java b/src/test/java/seedu/malitio/commons/util/XmlUtilTest.java similarity index 61% rename from src/test/java/seedu/address/commons/util/XmlUtilTest.java rename to src/test/java/seedu/malitio/commons/util/XmlUtilTest.java index dc4fd886c23e..a94682446d56 100644 --- a/src/test/java/seedu/address/commons/util/XmlUtilTest.java +++ b/src/test/java/seedu/malitio/commons/util/XmlUtilTest.java @@ -1,12 +1,15 @@ -package seedu.address.commons.util; +package seedu.malitio.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.model.AddressBook; -import seedu.address.storage.XmlSerializableAddressBook; -import seedu.address.testutil.AddressBookBuilder; -import seedu.address.testutil.TestUtil; + +import seedu.malitio.testutil.MalitioBuilder; +import seedu.malitio.testutil.TestUtil; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.commons.util.XmlUtil; +import seedu.malitio.model.Malitio; +import seedu.malitio.storage.XmlSerializableMalitio; import javax.xml.bind.JAXBException; import java.io.File; @@ -19,8 +22,8 @@ public class XmlUtilTest { private static final String TEST_DATA_FOLDER = FileUtil.getPath("src/test/data/XmlUtilTest/"); private static final File EMPTY_FILE = new File(TEST_DATA_FOLDER + "empty.xml"); private static final File MISSING_FILE = new File(TEST_DATA_FOLDER + "missing.xml"); - private static final File VALID_FILE = new File(TEST_DATA_FOLDER + "validAddressBook.xml"); - private static final File TEMP_FILE = new File(TestUtil.getFilePathInSandboxFolder("tempAddressBook.xml")); + private static final File VALID_FILE = new File(TEST_DATA_FOLDER + "validMalitio.xml"); + private static final File TEMP_FILE = new File(TestUtil.getFilePathInSandboxFolder("tempMalitio.xml")); @Rule public ExpectedException thrown = ExpectedException.none(); @@ -28,7 +31,7 @@ public class XmlUtilTest { @Test public void getDataFromFile_nullFile_AssertionError() throws Exception { thrown.expect(AssertionError.class); - XmlUtil.getDataFromFile(null, AddressBook.class); + XmlUtil.getDataFromFile(null, Malitio.class); } @Test @@ -40,26 +43,26 @@ public void getDataFromFile_nullClass_AssertionError() throws Exception { @Test public void getDataFromFile_missingFile_FileNotFoundException() throws Exception { thrown.expect(FileNotFoundException.class); - XmlUtil.getDataFromFile(MISSING_FILE, AddressBook.class); + XmlUtil.getDataFromFile(MISSING_FILE, Malitio.class); } @Test public void getDataFromFile_emptyFile_DataFormatMismatchException() throws Exception { thrown.expect(JAXBException.class); - XmlUtil.getDataFromFile(EMPTY_FILE, AddressBook.class); + XmlUtil.getDataFromFile(EMPTY_FILE, Malitio.class); } @Test public void getDataFromFile_validFile_validResult() throws Exception { - XmlSerializableAddressBook dataFromFile = XmlUtil.getDataFromFile(VALID_FILE, XmlSerializableAddressBook.class); - assertEquals(9, dataFromFile.getPersonList().size()); + XmlSerializableMalitio dataFromFile = XmlUtil.getDataFromFile(VALID_FILE, XmlSerializableMalitio.class); + assertEquals(9, dataFromFile.getFloatingTaskList().size()); assertEquals(0, dataFromFile.getTagList().size()); } @Test public void saveDataToFile_nullFile_AssertionError() throws Exception { thrown.expect(AssertionError.class); - XmlUtil.saveDataToFile(null, new AddressBook()); + XmlUtil.saveDataToFile(null, new Malitio()); } @Test @@ -71,23 +74,23 @@ public void saveDataToFile_nullClass_AssertionError() throws Exception { @Test public void saveDataToFile_missingFile_FileNotFoundException() throws Exception { thrown.expect(FileNotFoundException.class); - XmlUtil.saveDataToFile(MISSING_FILE, new AddressBook()); + XmlUtil.saveDataToFile(MISSING_FILE, new Malitio()); } @Test public void saveDataToFile_validFile_dataSaved() throws Exception { TEMP_FILE.createNewFile(); - XmlSerializableAddressBook dataToWrite = new XmlSerializableAddressBook(new AddressBook()); + XmlSerializableMalitio dataToWrite = new XmlSerializableMalitio(new Malitio()); XmlUtil.saveDataToFile(TEMP_FILE, dataToWrite); - XmlSerializableAddressBook dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableAddressBook.class); - assertEquals((new AddressBook(dataToWrite)).toString(),(new AddressBook(dataFromFile)).toString()); + XmlSerializableMalitio dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableMalitio.class); + assertEquals((new Malitio(dataToWrite)).toString(),(new Malitio(dataFromFile)).toString()); //TODO: use equality instead of string comparisons - AddressBookBuilder builder = new AddressBookBuilder(new AddressBook()); - dataToWrite = new XmlSerializableAddressBook(builder.withPerson(TestUtil.generateSamplePersonData().get(0)).withTag("Friends").build()); + MalitioBuilder builder = new MalitioBuilder(new Malitio()); + dataToWrite = new XmlSerializableMalitio(builder.withTask(TestUtil.generateSampleTaskData().get(0)).withTag("Friends").build()); XmlUtil.saveDataToFile(TEMP_FILE, dataToWrite); - dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableAddressBook.class); - assertEquals((new AddressBook(dataToWrite)).toString(),(new AddressBook(dataFromFile)).toString()); + dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableMalitio.class); + assertEquals((new Malitio(dataToWrite)).toString(),(new Malitio(dataFromFile)).toString()); } } diff --git a/src/test/java/seedu/malitio/logic/LogicManagerTest.java b/src/test/java/seedu/malitio/logic/LogicManagerTest.java new file mode 100644 index 000000000000..af99c2782a89 --- /dev/null +++ b/src/test/java/seedu/malitio/logic/LogicManagerTest.java @@ -0,0 +1,1061 @@ +package seedu.malitio.logic; + +import com.google.common.eventbus.Subscribe; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.events.model.MalitioChangedEvent; +import seedu.malitio.commons.events.ui.ShowHelpRequestEvent; +import seedu.malitio.logic.Logic; +import seedu.malitio.logic.LogicManager; +import seedu.malitio.logic.commands.*; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.Model; +import seedu.malitio.model.ModelManager; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; +import seedu.malitio.storage.StorageManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static seedu.malitio.commons.core.Messages.*; + +public class LogicManagerTest { + + /** + * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule + */ + @Rule + public TemporaryFolder saveFolder = new TemporaryFolder(); + + private Model model; + private Logic logic; + + //These are for checking the correctness of the events raised + private ReadOnlyMalitio latestSavedMalitio; + private boolean helpShown; + + @Subscribe + private void handleLocalModelChangedEvent(MalitioChangedEvent abce) { + latestSavedMalitio = new Malitio(abce.data); + } + + @Subscribe + private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) { + helpShown = true; + } + + @Before + public void setup() { + model = new ModelManager(); + String tempmalitioFile = saveFolder.getRoot().getPath() + "Tempmalitio.xml"; + String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json"; + logic = new LogicManager(model, new StorageManager(tempmalitioFile, tempPreferencesFile)); + EventsCenter.getInstance().registerHandler(this); + + latestSavedMalitio = new Malitio(model.getMalitio()); // last saved assumed to be up to date before. + helpShown = false; + } + + @After + public void teardown() { + EventsCenter.clearSubscribers(); + } + + @Test + public void execute_invalid() throws Exception { + String invalidCommand = " "; + assertCommandBehavior(invalidCommand, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + /** + * Executes the command and confirms that the result message is correct. + * Both the 'malitio' and the 'last shown list' are expected to be empty. + * @see #assertCommandBehavior(String, String, ReadOnlyMalitio, List) + */ + private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { + assertCommandBehavior(inputCommand, expectedMessage, new Malitio(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + } + + /** + * Executes the command and confirms that the result message is correct and + * also confirms that the following three parts of the LogicManager object's state are as expected:
+ * - the internal malitio data are same as those in the {@code expectedmalitio}
+ * - the backing list shown by UI matches the {@code shownList}
+ * - {@code expectedmalitio} was saved to the storage file.
+ */ + private void assertCommandBehavior(String inputCommand, String expectedMessage, + ReadOnlyMalitio expectedmalitio, + List expectedTaskShownList, + List expectedDeadlineShownList, + List expectedEventShownList) throws Exception { + + //Execute the command + CommandResult result = logic.execute(inputCommand); + + //Confirm the ui display elements should contain the right data + assertEquals(expectedMessage, result.feedbackToUser); + assertEquals(expectedTaskShownList, model.getFilteredFloatingTaskList()); + assertEquals(expectedDeadlineShownList, model.getFilteredDeadlineList()); + assertEquals(expectedEventShownList, model.getFilteredEventList()); + + //Confirm the state of data (saved and in-memory) is as expected + assertEquals(expectedmalitio, model.getMalitio()); + assertEquals(expectedmalitio, latestSavedMalitio); + } + + + @Test + public void execute_unknownCommandWord() throws Exception { + String unknownCommand = "uicfhmowqewca"; + assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND); + } + + @Test + public void execute_help() throws Exception { + assertCommandBehavior("help", HelpCommand.SHOWING_HELP_MESSAGE); + assertTrue(helpShown); + } + + @Test + public void execute_exit() throws Exception { + assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT); + } + + @Test + public void execute_clear() throws Exception { + TestDataHelper helper = new TestDataHelper(); + model.addTask(helper.generateTask(1)); + model.addTask(helper.generateTask(2)); + model.addTask(helper.generateTask(3)); + model.addTask(helper.generateDeadline(1)); + model.addTask(helper.generateDeadline(2)); + model.addTask(helper.generateDeadline(3)); + model.addTask(helper.generateEvent(1)); + model.addTask(helper.generateEvent(2)); + model.addTask(helper.generateEvent(3)); + + assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new Malitio(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + } + + + @Test + public void execute_add_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); + assertCommandBehavior( + "add Valid Name p/12345", expectedMessage); + } + + @Test + public void execute_add_invalidTask() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); + assertCommandBehavior( + "add dd//invalid ", expectedMessage); + assertCommandBehavior( + "add Valid t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); + + } + + //@@author A0129595N + @Test + public void execute_add_invalidDeadline() throws Exception { + String expectedMessage = DateTime.MESSAGE_DATETIME_CONSTRAINTS; + assertCommandBehavior( + "add do this by todayyy", expectedMessage); + } + + @Test + public void execute_add_invalidEvent() throws Exception { + String expectedMessage = Event.MESSAGE_INVALID_EVENT; + assertCommandBehavior( + "add do now start today end yesterday", expectedMessage); + } + + /** + * Test to make sure all three types of task can be added + * @throws Exception + */ + @Test + public void execute_add_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + FloatingTask floatingTaskToBeAdded = helper.sampleFloatingTask(); + Deadline deadlineToBeAdded = helper.sampleDeadline(); + Event eventToBeAdded = helper.sampleEvent(); + Malitio expectedAB = new Malitio(); + expectedAB.addTask(floatingTaskToBeAdded); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(floatingTaskToBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, floatingTaskToBeAdded), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + expectedAB.addTask(deadlineToBeAdded); + assertCommandBehavior(helper.generateAddCommand(deadlineToBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, deadlineToBeAdded), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + expectedAB.addTask(eventToBeAdded); + assertCommandBehavior(helper.generateAddCommand(eventToBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, eventToBeAdded), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + } + + @Test + public void execute_addDuplicate_notAllowed() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + FloatingTask floatingTaskToBeAdded = helper.sampleFloatingTask(); + Deadline deadlineToBeAdded = helper.sampleDeadline(); + Event eventToBeAdded = helper.sampleEvent(); + Malitio expectedAB = new Malitio(); + expectedAB.addTask(floatingTaskToBeAdded); + expectedAB.addTask(deadlineToBeAdded); + expectedAB.addTask(eventToBeAdded); + + // setup starting state + model.addTask(floatingTaskToBeAdded); // floating task already in internal Malitio + model.addTask(deadlineToBeAdded); // deadline already in internal Malitio + model.addTask(eventToBeAdded); // event already in internal Malitio + + // execute command and verify result for floating task + assertCommandBehavior( + helper.generateAddCommand(floatingTaskToBeAdded), + AddCommand.MESSAGE_DUPLICATE_TASK, + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // execute command and verify result for deadline + assertCommandBehavior( + helper.generateAddCommand(deadlineToBeAdded), + AddCommand.MESSAGE_DUPLICATE_DEADLINE, + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // execute command and verify result for event + assertCommandBehavior( + helper.generateAddCommand(eventToBeAdded), + AddCommand.MESSAGE_DUPLICATE_EVENT, + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + } + + //@@author + @Test + public void execute_list_showsAllTasks() throws Exception { + // prepare expectations + TestDataHelper helper = new TestDataHelper(); + Malitio expectedAB = helper.generateMalitio(2); + List expectedFloatingTaskList = expectedAB.getFloatingTaskList(); + List expectedDeadlineList = expectedAB.getDeadlineList(); + List expectedEventList = expectedAB.getEventList(); + + // prepare malitio state + helper.addToModel(model, 2); + + assertCommandBehavior("list", + ListCommand.ALL_MESSAGE_SUCCESS, + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + } + + //@@author A0122460W + @Test + public void execute_complete_tests() throws Exception { + + //generate data + TestDataHelper helper = new TestDataHelper(); + model.addTask(helper.generateTask(1)); + model.addTask(helper.generateDeadline(1)); + CommandResult result1 = logic.execute("complete f1"); + CommandResult result2 = logic.execute("complete d1"); + CommandResult result3 = logic.execute("complete f1"); + CommandResult result4 = logic.execute("complete d1"); + CommandResult result5 = logic.execute("complete f100"); + CommandResult result6 = logic.execute("complete d100"); + CommandResult result7 = logic.execute("complete asdf"); + CommandResult result8 = logic.execute("complete asdf"); + String expectedMessage1 = String.format(CompleteCommand.MESSAGE_COMPLETED_TASK_SUCCESS); + String expectedMessage2 = String.format(CompleteCommand.MESSAGE_COMPLETED_DEADLINE_SUCCESS); + String expectedMessage3 = String.format(CompleteCommand.MESSAGE_COMPLETED_TASK); + String expectedMessage4 = String.format(CompleteCommand.MESSAGE_COMPLETED_DEADLINE); + String expectedMessage5 = String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + String expectedMessage6 = String.format(MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + String expectedMessage7 = String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE); + String expectedMessage8 = String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE); + + //successful complete + assertEquals(result1.feedbackToUser, expectedMessage1); + assertEquals(result2.feedbackToUser, expectedMessage2); + assertEquals(model.getFilteredFloatingTaskList().get(0).getCompleted(), true); + assertEquals(model.getFilteredDeadlineList().get(0).getCompleted(),true); + + //cannot complete completed task + assertEquals(result3.feedbackToUser, expectedMessage3); + assertEquals(result4.feedbackToUser, expectedMessage4); + + //cannot complete invalid index + assertEquals(result5.feedbackToUser, expectedMessage5); + assertEquals(result6.feedbackToUser, expectedMessage6); + + //invalid complete argument + assertEquals(result7.feedbackToUser, expectedMessage7); + assertEquals(result8.feedbackToUser, expectedMessage8); + } + + @Test + public void execute_uncomplete_tests() throws Exception { + + //generate data + TestDataHelper helper = new TestDataHelper(); + model.addTask(helper.generateTask(1)); + model.addTask(helper.generateDeadline(1)); + logic.execute("complete f1"); + logic.execute("complete d1"); + CommandResult result1 = logic.execute("uncomplete f1"); + CommandResult result2 = logic.execute("uncomplete d1"); + CommandResult result3 = logic.execute("uncomplete f1"); + CommandResult result4 = logic.execute("uncomplete d1"); + CommandResult result5 = logic.execute("uncomplete f100"); + CommandResult result6 = logic.execute("uncomplete d100"); + CommandResult result7 = logic.execute("uncomplete asdf"); + CommandResult result8 = logic.execute("uncomplete asdf"); + String expectedMessage1 = String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_TASK_SUCCESS); + String expectedMessage2 = String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_DEADLINE_SUCCESS); + String expectedMessage3 = String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_TASK); + String expectedMessage4 = String.format(UncompleteCommand.MESSAGE_UNCOMPLETED_DEADLINE); + String expectedMessage5 = String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + String expectedMessage6 = String.format(MESSAGE_INVALID_DEADLINE_DISPLAYED_INDEX); + String expectedMessage7 = String.format(MESSAGE_INVALID_COMMAND_FORMAT, UncompleteCommand.MESSAGE_USAGE); + String expectedMessage8 = String.format(MESSAGE_INVALID_COMMAND_FORMAT, UncompleteCommand.MESSAGE_USAGE); + + //successful uncomplete + assertEquals(result1.feedbackToUser, expectedMessage1); + assertEquals(result2.feedbackToUser, expectedMessage2); + assertEquals(model.getFilteredFloatingTaskList().get(0).getCompleted(), false); + assertEquals(model.getFilteredDeadlineList().get(0).getCompleted(),false); + + + //cannot uncomplete uncompleted task + assertEquals(result3.feedbackToUser, expectedMessage3); + assertEquals(result4.feedbackToUser, expectedMessage4); + + //cannot uncomplete invalid index + assertEquals(result5.feedbackToUser, expectedMessage5); + assertEquals(result6.feedbackToUser, expectedMessage6); + + //invalid uncomplete argument + assertEquals(result7.feedbackToUser, expectedMessage7); + assertEquals(result8.feedbackToUser, expectedMessage8); + } + + @Test + public void execute_listall_test() throws Exception { + CommandResult result = logic.execute("listall"); + String expectedMessage = String.format(ListAllCommand.LISTALL_MESSAGE_SUCCESS); + assertEquals(result.feedbackToUser, expectedMessage); + } + + //@@author + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { + assertCommandBehavior(commandWord , expectedMessage); //index missing + assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0 + assertCommandBehavior(commandWord + " not_a_number", expectedMessage); + } + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { + String expectedMessage = MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + TestDataHelper helper = new TestDataHelper(); + List floatingTaskList = helper.generateFloatingTaskList(2); + List deadlineList = helper.generateDeadlineList(2); + List eventList = helper.generateEventList(2); + + // set AB state to 2 tasks each for floating tasks, deadlines and events + model.resetData(new Malitio()); + for (FloatingTask f : floatingTaskList) { + model.addTask(f); + } + for (Deadline d : deadlineList) { + model.addTask(d); + } + for (Event e : eventList) { + model.addTask(e); + } + + assertCommandBehavior(commandWord + " d3", expectedMessage, model.getMalitio(), floatingTaskList, deadlineList, eventList); + } + + @Test + public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage); + } + + @Test + public void execute_deleteIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("delete"); + } + + //@@author A0129595N + @Test + public void execute_delete_removesCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeFloatingTasks = helper.generateFloatingTaskList(3); + List fiveDeadlines = helper.generateDeadlineList(5); + List fourEvents = helper.generateEventList(4); + Malitio expectedAB = helper.generateMalitio(threeFloatingTasks, fiveDeadlines, fourEvents); + expectedAB.removeTask(threeFloatingTasks.get(1)); + helper.addToModel(model, threeFloatingTasks, fiveDeadlines, fourEvents); + + // execute command and verify result for floating task + assertCommandBehavior("delete f2", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, threeFloatingTasks.get(1)), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // execute command and verify result for deadline (boundary case) + expectedAB.removeTask(fiveDeadlines.get(0)); + assertCommandBehavior("delete d1", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, fiveDeadlines.get(0)), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // execute command and verify result for event (boundary case) + expectedAB.removeTask(fourEvents.get(3)); + assertCommandBehavior("delete e4", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, fourEvents.get(3)), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + } + //@@author + + @Test + public void execute_find_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); + assertCommandBehavior("find ", expectedMessage); + } + + //@@author A0129595N + @Test + public void execute_find_matchesPartialWordsInNames() throws Exception { + TestDataHelper helper = new TestDataHelper(); + FloatingTask fTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + FloatingTask fTarget2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + FloatingTask fTarget3 = helper.generateTaskWithName("KEYKEYKEY sduauo"); + FloatingTask f1 = helper.generateTaskWithName("KE Y"); + + Deadline dTarget1 = helper.generateDeadlineWithName("bla hey KEY bla"); + Deadline dTarget2 = helper.generateDeadlineWithName("KEY asdalksjdjas"); + Deadline d1 = helper.generateDeadlineWithName("K E Y"); + + Event eTarget1 = helper.generateEventWithName("askldj KEY"); + Event e1 = helper.generateEventWithName("LOL KLEY"); + + List fourTasks = helper.generateFloatingTaskList(f1, fTarget1, fTarget2, fTarget3); + List threeDeadlines = helper.generateDeadlineList(dTarget1, dTarget2, d1); + List twoEvents = helper.generateEventList(eTarget1, e1); + Malitio expectedAB = helper.generateMalitio(fourTasks, threeDeadlines, twoEvents); + List expectedFloatingTaskList = helper.generateFloatingTaskList(fTarget1, fTarget2, fTarget3); + List expectedDeadlineList = helper.generateDeadlineList(dTarget1, dTarget2); + List expectedEventList = helper.generateEventList(eTarget1); + helper.addToModel(model, fourTasks, threeDeadlines, twoEvents); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedFloatingTaskList.size() + expectedDeadlineList.size() + expectedEventList.size()), + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + } + + @Test + public void execute_find_isNotCaseSensitive() throws Exception { + TestDataHelper helper = new TestDataHelper(); + FloatingTask f1 = helper.generateTaskWithName("bla bla KEY bla"); + FloatingTask f2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + FloatingTask f3 = helper.generateTaskWithName("key key"); + FloatingTask f4 = helper.generateTaskWithName("KEy sduauo"); + + Deadline d1 = helper.generateDeadlineWithName("KeY"); + Deadline d2 = helper.generateDeadlineWithName("KeY KEY keY"); + Deadline d3 = helper.generateDeadlineWithName("Ksd KEY"); + + Event e1 = helper.generateEventWithName("KeY keY"); + Event e2 = helper.generateEventWithName("Kasdasd key"); + + List fourTasks = helper.generateFloatingTaskList(f3, f1, f4, f2); + List threeDeadlines = helper.generateDeadlineList(d1, d2, d3); + List twoEvents = helper.generateEventList(e1, e2); + Malitio expectedAB = helper.generateMalitio(fourTasks, threeDeadlines, twoEvents); + List expectedFloatingTaskList = fourTasks; + List expectedDeadlineList = threeDeadlines; + List expectedEventList = twoEvents; + helper.addToModel(model, fourTasks, threeDeadlines, twoEvents); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedFloatingTaskList.size() + expectedDeadlineList.size() + expectedEventList.size()), + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + } + + @Test + public void execute_find_matchesIfAnyKeywordPresent() throws Exception { + TestDataHelper helper = new TestDataHelper(); + FloatingTask fTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + FloatingTask fTarget2 = helper.generateTaskWithName("bla rAnDoM bla bceofeia"); + FloatingTask fTarget3 = helper.generateTaskWithName("key key"); + FloatingTask f1 = helper.generateTaskWithName("sduauo"); + + Deadline dTarget1 = helper.generateDeadlineWithName("bla bla KEY"); + Deadline dTarget2 = helper.generateDeadlineWithName("hehe rAnDoM"); + Deadline d1 = helper.generateDeadlineWithName("hello"); + + Event eTarget1 = helper.generateEventWithName("bla heyyy rAnDoM"); + Event eTarget2 = helper.generateEventWithName("rAnDoM lol"); + Event e1 = helper.generateEventWithName("i want to sleep"); + + List fourTasks = helper.generateFloatingTaskList(fTarget1, f1, fTarget2, fTarget3); + List threeDeadlines = helper.generateDeadlineList(dTarget1, dTarget2, d1); + List threeEvents = helper.generateEventList(eTarget1, eTarget2, e1); + Malitio expectedAB = helper.generateMalitio(fourTasks, threeDeadlines, threeEvents); + List expectedFloatingTaskList = helper.generateFloatingTaskList(fTarget1, fTarget2, fTarget3); + List expectedDeadlineList = helper.generateDeadlineList(dTarget1, dTarget2); + List expectedEventList = helper.generateEventList(eTarget1, eTarget2); + helper.addToModel(model, fourTasks, threeDeadlines, threeEvents); + + assertCommandBehavior("find key rAnDoM", + Command.getMessageForTaskListShownSummary(expectedFloatingTaskList.size() + expectedDeadlineList.size() + expectedEventList.size()), + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + } + + @Test + public void execute_find_withinEachTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + FloatingTask fTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + FloatingTask fTarget2 = helper.generateTaskWithName("bla rAnDoM bla bceofeia"); + FloatingTask fTarget3 = helper.generateTaskWithName("key key"); + FloatingTask f1 = helper.generateTaskWithName("sduauo"); + + Deadline dTarget1 = helper.generateDeadlineWithName("bla bla KEY"); + Deadline dTarget2 = helper.generateDeadlineWithName("hehe rAnDoM"); + Deadline d1 = helper.generateDeadlineWithName("hello"); + + Event eTarget1 = helper.generateEventWithName("bla heyyy KEY"); + Event eTarget2 = helper.generateEventWithName("rAnDoM lol"); + Event e1 = helper.generateEventWithName("i want to sleep"); + + //Setup Malitio to have 4 floating tasks, 3 deadlines and 3 events. + List fourTasks = helper.generateFloatingTaskList(fTarget1, f1, fTarget2, fTarget3); + List threeDeadlines = helper.generateDeadlineList(dTarget1, dTarget2, d1); + List threeEvents = helper.generateEventList(eTarget1, eTarget2, e1); + Malitio expectedAB = helper.generateMalitio(fourTasks, threeDeadlines, threeEvents); + + //Find within floating tasks + List expectedFloatingTaskList = helper.generateFloatingTaskList(fTarget1, fTarget2, fTarget3); + List expectedDeadlineList = helper.generateDeadlineList(dTarget1, dTarget2, d1); // deadline list is unchanged when finding other task + List expectedEventList = helper.generateEventList(eTarget1, eTarget2, e1); // event list is unchanged when finding other task + helper.addToModel(model, fourTasks, threeDeadlines, threeEvents); + + assertCommandBehavior("find f key rAnDoM", + Command.getMessageForTaskListShownSummary(expectedFloatingTaskList.size()), + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + + //Find within deadlines + expectedDeadlineList = helper.generateDeadlineList(dTarget1, dTarget2); + assertCommandBehavior("find d key rAnDoM", + Command.getMessageForTaskListShownSummary(expectedDeadlineList.size()), + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + + //Find within events + expectedEventList = helper.generateEventList(eTarget1, eTarget2); + assertCommandBehavior("find e key rAnDoM", + Command.getMessageForTaskListShownSummary(expectedDeadlineList.size()), + expectedAB, + expectedFloatingTaskList, + expectedDeadlineList, + expectedEventList); + + } + + @Test + public void execute_undoThenRedo_afterAdd() throws Exception { + TestDataHelper helper = new TestDataHelper(); + FloatingTask floatingTaskToBeAdded = helper.sampleFloatingTask(); + Malitio expectedAB = new Malitio(); + expectedAB.addTask(floatingTaskToBeAdded); + + //Since floating task, deadline and event are similar in terms of the way they are created + //and added to their respective list, we shall only test one of them (floating task) to save resources. + + //Confirm add floating task succeeds + assertCommandBehavior(helper.generateAddCommand(floatingTaskToBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, floatingTaskToBeAdded), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // remove task from expected + expectedAB.removeTask(floatingTaskToBeAdded); + // execute undo command and verify result + assertCommandBehavior("undo", + String.format(UndoCommand.MESSAGE_UNDO_ADD_SUCCESS, floatingTaskToBeAdded), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // add the task back to expected + expectedAB.addTask(floatingTaskToBeAdded); + // execute redo command and verify result + assertCommandBehavior("redo", + String.format(RedoCommand.MESSAGE_REDO_ADD_SUCCESS, floatingTaskToBeAdded), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + } + + @Test + public void execute_undoThenRedo_afterDelete() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List tasks = helper.generateFloatingTaskList(2); + List deadlines = helper.generateDeadlineList(2); + List events = helper.generateEventList(2); + Malitio expectedAB = helper.generateMalitio(tasks, deadlines, events); + helper.addToModel(model, tasks, deadlines, events); + + //Since floating task, deadline and event are similar in terms of the way they are deleted + //from their respective list, we shall only test one of them (deadline) to save resources. + + expectedAB.removeTask(deadlines.get(0)); + //Confirm delete deadline succeeds + assertCommandBehavior("delete d1", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, deadlines.get(0)), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // add task to expected + expectedAB.addTask(deadlines.get(0)); + // execute command and verify result + assertCommandBehavior("undo", + String.format(UndoCommand.MESSAGE_UNDO_DELETE_SUCCESS, deadlines.get(0)), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + + // remove task from expected + expectedAB.removeTask(deadlines.get(0)); + + // execute command and verify result + assertCommandBehavior("redo", + String.format(RedoCommand.MESSAGE_REDO_DELETE_SUCCESS, deadlines.get(0)), + expectedAB, + expectedAB.getFloatingTaskList(), + expectedAB.getDeadlineList(), + expectedAB.getEventList()); + } + + @Test + public void execute_undoThenRedo_afterClear() throws Exception { + + TestDataHelper helper = new TestDataHelper(); + // Initialize model with some tasks + List tasks = helper.generateFloatingTaskList(3); + List deadlines = helper.generateDeadlineList(3); + List events = helper.generateEventList(3); + Malitio expectedAB = helper.generateMalitio(tasks, deadlines, events); + helper.addToModel(model, tasks, deadlines, events); + + // Confirm model is cleared + assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new Malitio(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList()); + + // execute command and verify result + assertCommandBehavior("undo", UndoCommand.MESSAGE_UNDO_CLEAR_SUCCESS, expectedAB, + expectedAB.getFloatingTaskList(), expectedAB.getDeadlineList(), expectedAB.getEventList()); + + // execute command and verify result + assertCommandBehavior("redo", RedoCommand.MESSAGE_REDO_CLEAR_SUCCESS, new Malitio(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList()); + } + + @Test + public void execute_undoThenRedo_afterEdit() throws Exception { + TestDataHelper helper = new TestDataHelper(); + // Initialize model with some tasks + List tasks = helper.generateFloatingTaskList(2); + List deadlines = helper.generateDeadlineList(2); + List events = helper.generateEventList(2); + Malitio expectedAB = helper.generateMalitio(tasks, deadlines, events); + helper.addToModel(model, tasks, deadlines, events); + + // Confirm deadline is edited + Deadline editedDeadline = helper.generateDeadlineWithName("new deadlines"); + expectedAB.removeTask(deadlines.get(0)); + expectedAB.addTask(editedDeadline); + assertCommandBehavior("edit d1 new deadlines t/tag", String.format(EditCommand.MESSAGE_EDIT_TASK_SUCCESS, deadlines.get(0), editedDeadline), + expectedAB, expectedAB.getFloatingTaskList(), expectedAB.getDeadlineList(), expectedAB.getEventList()); + + // Revert expected to previous state before edit + expectedAB.addTask(deadlines.get(0)); + expectedAB.removeTask(editedDeadline); + + // Execute command and verify result + assertCommandBehavior("undo", String.format(UndoCommand.MESSAGE_UNDO_EDIT_SUCCESS, editedDeadline, deadlines.get(0)), expectedAB, + expectedAB.getFloatingTaskList(), expectedAB.getDeadlineList(), expectedAB.getEventList()); + + // Revert expected to previous state before undo + expectedAB.addTask(editedDeadline); + expectedAB.removeTask(deadlines.get(0)); + + // Execute command and verify result + assertCommandBehavior("redo", String.format(RedoCommand.MESSAGE_REDO_EDIT_SUCCESS, deadlines.get(0), editedDeadline), expectedAB, + expectedAB.getFloatingTaskList(), expectedAB.getDeadlineList(), expectedAB.getEventList()); + + } + //@@author + + + /** + * A utility class to generate test data. + */ + class TestDataHelper{ + + FloatingTask sampleFloatingTask() throws Exception { + Name task = new Name("Eat lunch"); + Tag tag1 = new Tag("tag1"); + Tag tag2 = new Tag("tag2"); + UniqueTagList tags = new UniqueTagList(tag1, tag2); + return new FloatingTask(task, tags); + } + + Deadline sampleDeadline() throws Exception { + Name deadline = new Name("Buy food"); + DateTime due = new DateTime("tomorrow 3pm"); + Tag tag1 = new Tag("tag1"); + Tag tag2 = new Tag("tag2"); + UniqueTagList tags = new UniqueTagList(tag1, tag2); + return new Deadline(deadline, due, tags); + } + + Event sampleEvent() throws Exception { + Name event = new Name("lecture"); + DateTime start = new DateTime("next week 12pm"); + DateTime end = new DateTime("next week 2pm"); + Tag tag1 = new Tag("tag1"); + Tag tag2 = new Tag("tag2"); + UniqueTagList tags = new UniqueTagList(tag1, tag2); + return new Event(event, start, end, tags); + } + + /** + * Generates a valid Floating Task using the given seed. + * Running this function with the same parameter values guarantees the returned Floating Task will have the same state. + * Each unique seed will generate a unique Floating Task object. + * + * @param seed used to generate the task data field values + */ + FloatingTask generateTask(int seed) throws Exception { + return new FloatingTask(new Name("Task " + seed), + new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1)))); + } + + /** + * Generates a valid deadline using the given seed. + * Running this function with the same parameter values guarantees the returned Deadline will have the same state. + * Each unique seed will generate a unique Deadline object. + * + * @param seed used to generate the task data field values + */ + Deadline generateDeadline(int seed) throws Exception { + return new Deadline(new Name("Deadline " + seed), new DateTime("tomorrow 3pm"), + new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1)))); + } + + /** + * Generates a valid event using the given seed. + * Running this function with the same parameter values guarantees the returned event will have the same state. + * Each unique seed will generate a unique Event object. + * + * @param seed used to generate the task data field values + */ + Event generateEvent(int seed) throws Exception { + return new Event(new Name("Deadline " + seed), new DateTime("tomorrow 3pm"), new DateTime("next week 4pm"), + new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1)))); + } + + //@@author A0129595N + /** Generates the correct add command based on the task given */ + String generateAddCommand(Object p) { + StringBuffer cmd = new StringBuffer(); + cmd.append("add "); + if (isFloatingTask(p)) { + cmd.append(getArgFromFloatingTaskObj(p)); + } else if (isDeadline(p)) { + cmd.append(getArgFromDeadlineObj(p)); + } else { + cmd.append(getArgFromEventObj(p)); + } + return cmd.toString(); + } + + /** + * Helper method to get the arguments for Floating Task + * @param p Floating Task Object + */ + private String getArgFromFloatingTaskObj(Object p) { + StringBuffer arg = new StringBuffer(); + arg.append(((FloatingTask) p).getName().fullName); + UniqueTagList tags = ((FloatingTask) p).getTags(); + for (Tag t : tags) { + arg.append(" t/").append(t.tagName); + } + return arg.toString(); + } + + /** + * Helper method to get the arguments for Deadline + * @param p Deadline Object + */ + private String getArgFromDeadlineObj(Object p) { + StringBuffer arg = new StringBuffer(); + arg.append(((Deadline) p).getName().fullName); + arg.append(" by "); + arg.append(((Deadline) p).getDue().toString()); + UniqueTagList tags = ((Deadline) p).getTags(); + for (Tag t : tags) { + arg.append(" t/").append(t.tagName); + } + return arg.toString(); + } + + /** + * Helper method to get the arguments for Event + * @param p Event Object + */ + private String getArgFromEventObj(Object p) { + StringBuffer arg = new StringBuffer(); + arg.append(((Event) p).getName().fullName); + arg.append(" start "); + arg.append(((Event) p).getStart().toString()); + arg.append(" end "); + arg.append(((Event) p).getEnd().toString()); + UniqueTagList tags = ((Event) p).getTags(); + for (Tag t : tags) { + arg.append(" t/").append(t.tagName); + } + return arg.toString(); + } + + boolean isFloatingTask(Object p) { + return p instanceof FloatingTask; + } + + boolean isDeadline(Object p) { + return p instanceof Deadline; + } + //@@author + /** + * Generates Malitio with auto-generated tasks. + */ + Malitio generateMalitio(int numGenerated) throws Exception{ + Malitio malitio = new Malitio(); + addToMalitio(malitio, numGenerated); + return malitio; + } + + /** + * Generates Malitio based on the list of Tasks given. + */ + Malitio generateMalitio(List tasks, List deadlines, List events) throws Exception{ + Malitio malitio = new Malitio(); + addToMalitio(malitio, tasks, deadlines, events); + return malitio; + } + + /** + * Adds auto-generated Task objects to the given Malitio + * @param The malitio to which the Tasks will be added + */ + void addToMalitio(Malitio malitio, int numGenerated) throws Exception{ + addToMalitio(malitio, generateFloatingTaskList(numGenerated), generateDeadlineList(numGenerated), generateEventList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given Malitio + */ + void addToMalitio(Malitio malitio, List tasksToAdd, List deadlinesToAdd, List eventsToAdd) throws Exception{ + for(FloatingTask p: tasksToAdd){ + malitio.addTask(p); + } + for (Deadline d: deadlinesToAdd) { + malitio.addTask(d); + } + for (Event e: eventsToAdd) { + malitio.addTask(e); + } + } + + /** + * Adds auto-generated Task objects to the given model + * @param model The model to which the Tasks will be added + */ + void addToModel(Model model, int numGenerated) throws Exception{ + addToModel(model, generateFloatingTaskList(numGenerated), generateDeadlineList(numGenerated), generateEventList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given model + */ + void addToModel(Model model, List tasksToAdd, List deadlinesToAdd, List eventsToAdd) throws Exception{ + for(FloatingTask p: tasksToAdd){ + model.addTask(p); + } + for (Deadline d: deadlinesToAdd) { + model.addTask(d); + } + for (Event e: eventsToAdd) { + model.addTask(e); + } + } + + /** + * Generates a list of Tasks based on the flags. + */ + List generateFloatingTaskList(int numGenerated) throws Exception{ + List tasks = new ArrayList<>(); + for(int i = 1; i <= numGenerated; i++){ + tasks.add(generateTask(i)); + } + return tasks; + } + + List generateFloatingTaskList(FloatingTask... floatingtasks) { + return Arrays.asList(floatingtasks); + } + + /** + * Generates a list of Deadlines based on the flags. + */ + List generateDeadlineList(int numGenerated) throws Exception{ + List deadlines = new ArrayList<>(); + for(int i = 1; i <= numGenerated; i++){ + deadlines.add(generateDeadline(i)); + } + return deadlines; + } + + List generateDeadlineList(Deadline... deadlines) { + return Arrays.asList(deadlines); + } + + /** + * Generates a list of Events based on the flags. + */ + List generateEventList(int numGenerated) throws Exception{ + List events = new ArrayList<>(); + for(int i = 1; i <= numGenerated; i++){ + events.add(generateEvent(i)); + } + return events; + } + + List generateEventList(Event... events) { + return Arrays.asList(events); + } + + /** + * Generates a Floating Task object with given name. Other fields will have some dummy values. + */ + FloatingTask generateTaskWithName(String name) throws Exception { + return new FloatingTask( + new Name(name), + new UniqueTagList(new Tag("tag")) + ); + } + + /** + * Generates a Deadline object with given name. Other fields will have some dummy values + */ + Deadline generateDeadlineWithName(String name) throws Exception { + return new Deadline(new Name(name), + new DateTime("tomorrow 3pm"), + new UniqueTagList(new Tag("tag")) + ); + } + + /** + * Generates a Event object with given name. Other fields will have some dummy values + */ + Event generateEventWithName(String name) throws Exception { + return new Event(new Name(name), + new DateTime("tomorrow 3pm"), + new DateTime("next week 5pm"), + new UniqueTagList(new Tag("tag")) + ); + } + } +} + diff --git a/src/test/java/seedu/address/model/UnmodifiableObservableListTest.java b/src/test/java/seedu/malitio/model/UnmodifiableObservableListTest.java similarity index 93% rename from src/test/java/seedu/address/model/UnmodifiableObservableListTest.java rename to src/test/java/seedu/malitio/model/UnmodifiableObservableListTest.java index 0334d7e42073..a72cf8b379b3 100644 --- a/src/test/java/seedu/address/model/UnmodifiableObservableListTest.java +++ b/src/test/java/seedu/malitio/model/UnmodifiableObservableListTest.java @@ -1,16 +1,17 @@ -package seedu.address.model; +package seedu.malitio.model; import javafx.collections.FXCollections; +import seedu.malitio.commons.core.UnmodifiableObservableList; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.commons.core.UnmodifiableObservableList; import java.util.*; import static org.junit.Assert.assertSame; -import static seedu.address.testutil.TestUtil.assertThrows; +import static seedu.malitio.testutil.TestUtil.assertThrows; public class UnmodifiableObservableListTest { diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/malitio/storage/JsonUserPrefsStorageTest.java similarity index 94% rename from src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java rename to src/test/java/seedu/malitio/storage/JsonUserPrefsStorageTest.java index 4e87203611be..603775260e55 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/seedu/malitio/storage/JsonUserPrefsStorageTest.java @@ -1,13 +1,15 @@ -package seedu.address.storage; +package seedu.malitio.storage; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.UserPrefs; + +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.model.UserPrefs; +import seedu.malitio.storage.JsonUserPrefsStorage; import java.io.File; import java.io.IOException; diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/malitio/storage/StorageManagerTest.java similarity index 53% rename from src/test/java/seedu/address/storage/StorageManagerTest.java rename to src/test/java/seedu/malitio/storage/StorageManagerTest.java index 6780feab6afc..faee54631189 100644 --- a/src/test/java/seedu/address/storage/StorageManagerTest.java +++ b/src/test/java/seedu/malitio/storage/StorageManagerTest.java @@ -1,17 +1,22 @@ -package seedu.address.storage; +package seedu.malitio.storage; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; -import seedu.address.testutil.TypicalTestPersons; -import seedu.address.testutil.EventsCollector; + +import seedu.malitio.testutil.TypicalTestTasks; +import seedu.malitio.commons.events.model.MalitioChangedEvent; +import seedu.malitio.commons.events.storage.DataSavingExceptionEvent; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.UserPrefs; +import seedu.malitio.storage.JsonUserPrefsStorage; +import seedu.malitio.storage.Storage; +import seedu.malitio.storage.StorageManager; +import seedu.malitio.storage.XmlMalitioStorage; +import seedu.malitio.testutil.EventsCollector; import java.io.IOException; @@ -54,25 +59,25 @@ public void prefsReadSave() throws Exception { } @Test - public void addressBookReadSave() throws Exception { - AddressBook original = new TypicalTestPersons().getTypicalAddressBook(); - storageManager.saveAddressBook(original); - ReadOnlyAddressBook retrieved = storageManager.readAddressBook().get(); - assertEquals(original, new AddressBook(retrieved)); - //More extensive testing of AddressBook saving/reading is done in XmlAddressBookStorageTest + public void malitioReadSave() throws Exception { + Malitio original = new TypicalTestTasks().getTypicalMalitio(); + storageManager.saveMalitio(original); + ReadOnlyMalitio retrieved = storageManager.readMalitio().get(); + assertEquals(original, new Malitio(retrieved)); + //More extensive testing of Malitio saving/reading is done in XmlmalitioStorageTest } @Test - public void getAddressBookFilePath(){ - assertNotNull(storageManager.getAddressBookFilePath()); + public void getMalitioFilePath(){ + assertNotNull(storageManager.getMalitioFilePath()); } @Test - public void handleAddressBookChangedEvent_exceptionThrown_eventRaised() throws IOException { + public void handleMalitioChangedEvent_exceptionThrown_eventRaised() throws IOException { //Create a StorageManager while injecting a stub that throws an exception when the save method is called - Storage storage = new StorageManager(new XmlAddressBookStorageExceptionThrowingStub("dummy"), new JsonUserPrefsStorage("dummy")); + Storage storage = new StorageManager(new XmlmalitioStorageExceptionThrowingStub("dummy"), new JsonUserPrefsStorage("dummy")); EventsCollector eventCollector = new EventsCollector(); - storage.handleAddressBookChangedEvent(new AddressBookChangedEvent(new AddressBook())); + storage.handleMalitioChangedEvent(new MalitioChangedEvent(new Malitio())); assertTrue(eventCollector.get(0) instanceof DataSavingExceptionEvent); } @@ -80,17 +85,15 @@ public void handleAddressBookChangedEvent_exceptionThrown_eventRaised() throws I /** * A Stub class to throw an exception when the save method is called */ - class XmlAddressBookStorageExceptionThrowingStub extends XmlAddressBookStorage{ + class XmlmalitioStorageExceptionThrowingStub extends XmlMalitioStorage { - public XmlAddressBookStorageExceptionThrowingStub(String filePath) { + public XmlmalitioStorageExceptionThrowingStub(String filePath) { super(filePath); } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) throws IOException { + public void saveMalitio(ReadOnlyMalitio malitio, String filePath) throws IOException { throw new IOException("dummy exception"); } } - - } diff --git a/src/test/java/seedu/malitio/storage/XmlMalitioStorageTest.java b/src/test/java/seedu/malitio/storage/XmlMalitioStorageTest.java new file mode 100644 index 000000000000..a2c090e22232 --- /dev/null +++ b/src/test/java/seedu/malitio/storage/XmlMalitioStorageTest.java @@ -0,0 +1,108 @@ +package seedu.malitio.storage; + + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; + +import seedu.malitio.testutil.TypicalTestTasks; +import seedu.malitio.commons.exceptions.DataConversionException; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.ReadOnlyMalitio; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.FloatingTask; +import seedu.malitio.storage.XmlMalitioStorage; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +public class XmlMalitioStorageTest { + private static String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/XmlMalitioStorageTest/"); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + public TemporaryFolder testFolder = new TemporaryFolder(); + + @Test + public void readMalitio_nullFilePath_assertionFailure() throws Exception { + thrown.expect(AssertionError.class); + readMalitio(null); + } + + private java.util.Optional readMalitio(String filePath) throws Exception { + return new XmlMalitioStorage(filePath).readMalitio(addToTestDataPathIfNotNull(filePath)); + } + + private String addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) { + return prefsFileInTestDataFolder != null + ? TEST_DATA_FOLDER + prefsFileInTestDataFolder + : null; + } + + @Test + public void read_missingFile_emptyResult() throws Exception { + assertFalse(readMalitio("NonExistentFile.xml").isPresent()); + } + + @Test + public void read_notXmlFormat_exceptionThrown() throws Exception { + + thrown.expect(DataConversionException.class); + readMalitio("NotXmlFormatMalitio.xml"); + + /* IMPORTANT: Any code below an exception-throwing line (like the one above) will be ignored. + * That means you should not have more than one exception test in one method + */ + } + + @Test + public void readAndSaveMalitio_allInOrder_success() throws Exception { + String filePath = testFolder.getRoot().getPath() + "Tempmalitio.xml"; + TypicalTestTasks td = new TypicalTestTasks(); + Malitio original = td.getTypicalMalitio(); + XmlMalitioStorage xmlMalitioStorage = new XmlMalitioStorage(filePath); + + //Save in new file and read back + xmlMalitioStorage.saveMalitio(original, filePath); + ReadOnlyMalitio readBack = xmlMalitioStorage.readMalitio(filePath).get(); + assertEquals(original, new Malitio(readBack)); + + //Modify data, overwrite exiting file, and read back + original.addTask(new FloatingTask(TypicalTestTasks.manualFloatingTask1)); + original.removeTask(new FloatingTask(TypicalTestTasks.floatingTask1)); + xmlMalitioStorage.saveMalitio(original, filePath); + readBack = xmlMalitioStorage.readMalitio(filePath).get(); + assertEquals(original, new Malitio(readBack)); + + //Save and read without specifying file path + original.addTask(new Deadline(TypicalTestTasks.manualDeadline1)); + xmlMalitioStorage.saveMalitio(original); //file path not specified + readBack = xmlMalitioStorage.readMalitio().get(); //file path not specified + assertEquals(original, new Malitio(readBack)); + + } + + @Test + public void savemalitio_nullmalitio_assertionFailure() throws IOException { + thrown.expect(AssertionError.class); + savemalitio(null, "SomeFile.xml"); + } + + private void savemalitio(ReadOnlyMalitio malitio, String filePath) throws IOException { + new XmlMalitioStorage(filePath).saveMalitio(malitio, addToTestDataPathIfNotNull(filePath)); + } + + @Test + public void savemalitio_nullFilePath_assertionFailure() throws IOException { + thrown.expect(AssertionError.class); + savemalitio(new Malitio(), null); + } + + +} diff --git a/src/test/java/seedu/malitio/testutil/DeadlineBuilder.java b/src/test/java/seedu/malitio/testutil/DeadlineBuilder.java new file mode 100644 index 000000000000..9364a7c31ebf --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/DeadlineBuilder.java @@ -0,0 +1,39 @@ +package seedu.malitio.testutil; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.task.*; + +/** + *Builds a deadline + */ +public class DeadlineBuilder { + + private TestDeadline task; + + public DeadlineBuilder() { + this.task = new TestDeadline(); + } + + public DeadlineBuilder withName(String name) throws IllegalValueException { + this.task.setName(new Name(name)); + return this; + } + + public DeadlineBuilder dueOn(String due) throws IllegalValueException { + this.task.setDue(new DateTime(due)); + return this; + } + + public DeadlineBuilder withTags(String ... tags) throws IllegalValueException { + for (String tag: tags) { + task.getTags().add(new Tag(tag)); + } + return this; + } + + public TestDeadline build() { + return this.task; + } + +} diff --git a/src/test/java/seedu/malitio/testutil/EventBuilder.java b/src/test/java/seedu/malitio/testutil/EventBuilder.java new file mode 100644 index 000000000000..534725361005 --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/EventBuilder.java @@ -0,0 +1,43 @@ +package seedu.malitio.testutil; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.task.*; + +/** + *Builds an event + */ +public class EventBuilder { + + private TestEvent event; + + public EventBuilder() { + this.event = new TestEvent(); + } + + public EventBuilder withName(String name) throws IllegalValueException { + this.event.setName(new Name(name)); + return this; + } + + public EventBuilder start(String start) throws IllegalValueException { + this.event.setStart(new DateTime(start)); + return this; + } + public EventBuilder end(String end) throws IllegalValueException { + this.event.setEnd(new DateTime(end)); + return this; + } + + public EventBuilder withTags(String ... tags) throws IllegalValueException { + for (String tag: tags) { + event.getTags().add(new Tag(tag)); + } + return this; + } + + public TestEvent build() { + return this.event; + } + +} diff --git a/src/test/java/seedu/address/testutil/EventsCollector.java b/src/test/java/seedu/malitio/testutil/EventsCollector.java similarity index 85% rename from src/test/java/seedu/address/testutil/EventsCollector.java rename to src/test/java/seedu/malitio/testutil/EventsCollector.java index c44d6ca6f95a..1d986fff42b0 100644 --- a/src/test/java/seedu/address/testutil/EventsCollector.java +++ b/src/test/java/seedu/malitio/testutil/EventsCollector.java @@ -1,8 +1,9 @@ -package seedu.address.testutil; +package seedu.malitio.testutil; import com.google.common.eventbus.Subscribe; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.BaseEvent; + +import seedu.malitio.commons.core.EventsCenter; +import seedu.malitio.commons.events.BaseEvent; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/seedu/malitio/testutil/FloatingTaskBuilder.java b/src/test/java/seedu/malitio/testutil/FloatingTaskBuilder.java new file mode 100644 index 000000000000..b781a60e2e5d --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/FloatingTaskBuilder.java @@ -0,0 +1,34 @@ +package seedu.malitio.testutil; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.task.*; + +/** + *Builds a floating task + */ +public class FloatingTaskBuilder { + + private TestFloatingTask Task; + + public FloatingTaskBuilder() { + this.Task = new TestFloatingTask(); + } + + public FloatingTaskBuilder withName(String name) throws IllegalValueException { + this.Task.setName(new Name(name)); + return this; + } + + public FloatingTaskBuilder withTags(String ... tags) throws IllegalValueException { + for (String tag: tags) { + Task.getTags().add(new Tag(tag)); + } + return this; + } + + public TestFloatingTask build() { + return this.Task; + } + +} diff --git a/src/test/java/seedu/malitio/testutil/MalitioBuilder.java b/src/test/java/seedu/malitio/testutil/MalitioBuilder.java new file mode 100644 index 000000000000..a36e1f0a67ae --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/MalitioBuilder.java @@ -0,0 +1,53 @@ +package seedu.malitio.testutil; + +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.task.Deadline; +import seedu.malitio.model.task.Event; +import seedu.malitio.model.task.FloatingTask; +import seedu.malitio.model.task.ReadOnlyFloatingTask; +import seedu.malitio.model.task.UniqueDeadlineList; +import seedu.malitio.model.task.UniqueDeadlineList.DuplicateDeadlineException; +import seedu.malitio.model.task.UniqueEventList; +import seedu.malitio.model.task.UniqueEventList.DuplicateEventException; +import seedu.malitio.model.task.UniqueFloatingTaskList; +import seedu.malitio.model.task.UniqueFloatingTaskList.DuplicateFloatingTaskException; + +/** + * A utility class to help with building malitio objects. + * Example usage:
+ * {@code malitio ab = new malitioBuilder().withTask("Eat", "Sleep").withTag("Friend").build();} + */ +public class MalitioBuilder { + + private Malitio malitio; + + public MalitioBuilder(Malitio malitio) { + this.malitio = malitio; + } + + public MalitioBuilder withTask(FloatingTask task) throws DuplicateFloatingTaskException, DuplicateDeadlineException, DuplicateEventException { + malitio.addTask(task); + return this; + } + + public MalitioBuilder withDeadline(Deadline deadline) throws DuplicateDeadlineException, DuplicateFloatingTaskException, DuplicateEventException { + malitio.addTask(deadline); + return this; + } + + public MalitioBuilder withEvent(Event event) throws UniqueEventList.DuplicateEventException, DuplicateFloatingTaskException, DuplicateDeadlineException { + malitio.addTask(event); + return this; + } + + public MalitioBuilder withTag(String tagName) throws IllegalValueException { + malitio.addTag(new Tag(tagName)); + return this; + } + + public Malitio build(){ + return malitio; + } +} diff --git a/src/test/java/seedu/address/testutil/SerializableTestClass.java b/src/test/java/seedu/malitio/testutil/SerializableTestClass.java similarity index 98% rename from src/test/java/seedu/address/testutil/SerializableTestClass.java rename to src/test/java/seedu/malitio/testutil/SerializableTestClass.java index ef58ef857179..a8d52969b266 100644 --- a/src/test/java/seedu/address/testutil/SerializableTestClass.java +++ b/src/test/java/seedu/malitio/testutil/SerializableTestClass.java @@ -1,4 +1,4 @@ -package seedu.address.testutil; +package seedu.malitio.testutil; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/src/test/java/seedu/malitio/testutil/TestDeadline.java b/src/test/java/seedu/malitio/testutil/TestDeadline.java new file mode 100644 index 000000000000..c232786ea430 --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/TestDeadline.java @@ -0,0 +1,86 @@ +package seedu.malitio.testutil; + +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; + +/** + * A mutable deadline object. For testing only. + */ +public class TestDeadline implements ReadOnlyDeadline { + + private Name name; + private DateTime due; + private boolean completed = false; + private boolean marked = false; + private UniqueTagList tags; + + public TestDeadline() { + tags = new UniqueTagList(); + } + + public void setName(Name name) { + this.name = name; + } + + @Override + public Name getName() { + return name; + } + + @Override + public UniqueTagList getTags() { + return tags; + } + + @Override + public String toString() { + return getAsText(); + } + + public String getAddCommand() { + StringBuilder sb = new StringBuilder(); + sb.append("add " + this.getName().fullName + " " + "by " + this.getDue().toString()); + this.getTags().getInternalList().stream().forEach(s -> sb.append(" t/" + s.tagName + " ")); + return sb.toString(); + } + + + public DateTime getDue() { + return due; + } + + + public void setDue(DateTime due) { + this.due = due; + } + + @Override + public String tagsString() { + return ReadOnlyDeadline.super.tagsString(); + } + + @Override + public String getAsText() { + return ReadOnlyDeadline.super.getAsText(); + } + + @Override + public boolean getCompleted() { + return completed; + } + + @Override + public void setCompleted(boolean complete) { + this.completed = complete; + } + + @Override + public boolean isMarked() { + return marked; + } + + @Override + public void setMarked(boolean marked) { + this.marked = marked; + } +} diff --git a/src/test/java/seedu/malitio/testutil/TestEvent.java b/src/test/java/seedu/malitio/testutil/TestEvent.java new file mode 100644 index 000000000000..a0c1b609ab1f --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/TestEvent.java @@ -0,0 +1,82 @@ +package seedu.malitio.testutil; + +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; + +/** + * A mutable event object. For testing only. + */ +public class TestEvent implements ReadOnlyEvent { + + private Name name; + private DateTime start; + private DateTime end; + private boolean marked; + private UniqueTagList tags; + + public TestEvent() { + tags = new UniqueTagList(); + } + + public void setName(Name name) { + this.name = name; + } + + @Override + public Name getName() { + return name; + } + + @Override + public UniqueTagList getTags() { + return tags; + } + + @Override + public String toString() { + return getAsText(); + } + + public String getAddCommand() { + StringBuilder sb = new StringBuilder(); + sb.append("add " + this.getName().fullName + " start " + this.getStart().toString() + " end " + this.getEnd().toString()); + this.getTags().getInternalList().stream().forEach(s -> sb.append(" t/" + s.tagName + " ")); + return sb.toString(); + } + + public DateTime getStart() { + return start; + } + + public void setStart(DateTime start) { + this.start = start; + } + + public DateTime getEnd() { + return end; + } + + public void setEnd(DateTime end) { + this.end = end; + } + + @Override + public String tagsString() { + return ReadOnlyEvent.super.tagsString(); + } + + @Override + public String getAsText() { + return ReadOnlyEvent.super.getAsText(); + } + + @Override + public boolean isMarked() { + return marked; + } + + @Override + public void setMarked(boolean marked) { + this.marked = marked; + } +} diff --git a/src/test/java/seedu/malitio/testutil/TestFloatingTask.java b/src/test/java/seedu/malitio/testutil/TestFloatingTask.java new file mode 100644 index 000000000000..332effad9329 --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/TestFloatingTask.java @@ -0,0 +1,75 @@ +package seedu.malitio.testutil; + +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; + +/** + * A mutable floating task object. For testing only. + */ +public class TestFloatingTask implements ReadOnlyFloatingTask { + + private Name name; + private boolean completed = false; + private boolean marked = false; + private UniqueTagList tags; + + public TestFloatingTask() { + tags = new UniqueTagList(); + } + + public void setName(Name name) { + this.name = name; + } + + @Override + public Name getName() { + return name; + } + + @Override + public UniqueTagList getTags() { + return tags; + } + + @Override + public String toString() { + return getAsText(); + } + + public String getAddCommand() { + StringBuilder sb = new StringBuilder(); + sb.append("add " + this.getName().fullName + " "); + this.getTags().getInternalList().stream().forEach(s -> sb.append("t/" + s.tagName + " ")); + return sb.toString(); + } + + @Override + public String tagsString() { + return ReadOnlyFloatingTask.super.tagsString(); + } + + @Override + public String getAsText() { + return ReadOnlyFloatingTask.super.getAsText(); + } + + @Override + public boolean getCompleted() { + return completed; + } + + @Override + public void setCompleted(boolean complete) { + this.completed = complete; + } + + @Override + public boolean isMarked() { + return marked; + } + + @Override + public void setMarked(boolean marked) { + this.marked = marked; + } +} diff --git a/src/test/java/seedu/malitio/testutil/TestUtil.java b/src/test/java/seedu/malitio/testutil/TestUtil.java new file mode 100644 index 000000000000..aa4c4e760334 --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/TestUtil.java @@ -0,0 +1,448 @@ +package seedu.malitio.testutil; + +import com.google.common.io.Files; + +import guitests.guihandles.DeadlineCardHandle; +import guitests.guihandles.EventCardHandle; +import guitests.guihandles.FloatingTaskCardHandle; +import javafx.geometry.Bounds; +import javafx.geometry.Point2D; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import junit.framework.AssertionFailedError; +import org.loadui.testfx.GuiTest; +import org.testfx.api.FxToolkit; +import seedu.malitio.TestApp; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.commons.util.FileUtil; +import seedu.malitio.commons.util.XmlUtil; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.tag.Tag; +import seedu.malitio.model.tag.UniqueTagList; +import seedu.malitio.model.task.*; +import seedu.malitio.storage.XmlSerializableMalitio; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +/** + * A utility class for test cases. + */ +public class TestUtil { + + public static String LS = System.lineSeparator(); + + public static void assertThrows(Class expected, Runnable executable) { + try { + executable.run(); + } + catch (Throwable actualException) { + if (!actualException.getClass().isAssignableFrom(expected)) { + String message = String.format("Expected thrown: %s, actual: %s", expected.getName(), + actualException.getClass().getName()); + throw new AssertionFailedError(message); + } else return; + } + throw new AssertionFailedError( + String.format("Expected %s to be thrown, but nothing was thrown.", expected.getName())); + } + + /** + * Folder used for temp files created during testing. Ignored by Git. + */ + public static String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); + + public static final FloatingTask[] sampleFloatingTaskData = getSampleTaskData(); + public static final Deadline[] sampleDeadlineData = getSampleDeadlineData(); + public static final Event[] sampleEventData = getSampleEventData(); + + private static FloatingTask[] getSampleTaskData() { + return new FloatingTask[] { new FloatingTask(new Name("adjust meter"), new UniqueTagList()), + new FloatingTask(new Name("bring along notes"), new UniqueTagList()), + new FloatingTask(new Name("copy answer"), new UniqueTagList()), + new FloatingTask(new Name("do some sit-up"), new UniqueTagList()), + new FloatingTask(new Name("eat with mom"), new UniqueTagList()), + new FloatingTask(new Name("forgive and forget"), new UniqueTagList()), + new FloatingTask(new Name("go shopping"), new UniqueTagList()), + new FloatingTask(new Name("hopping"), new UniqueTagList()), + new FloatingTask(new Name("Ida Mueller"), new UniqueTagList()) }; + + } + + private static Event[] getSampleEventData() { + try { + return new Event[]{ + new Event(new Name("Zen Birthday Celebration"), new DateTime("10-20 1100"), new DateTime("10-20 1200"), new UniqueTagList()), + new Event(new Name("JuMin Speech"), new DateTime("11-20 1100"), new DateTime("11-20 1200"), new UniqueTagList()), + new Event(new Name("STxxxx Lecture"), new DateTime("10-03 0000"), new DateTime("10-03 1000"), new UniqueTagList()), + new Event(new Name("My Birthday"), new DateTime("03-20 0000"), new DateTime("03-20 2359"), new UniqueTagList()), + new Event(new Name("Dinner Date with YooSung"), new DateTime("02-18-2017 1100"), new DateTime("02-19-2017 1200"), new UniqueTagList()), + new Event(new Name("Play Dota with Friends"), new DateTime("12-02-2016 0000"), new DateTime("12-02-2016 2359"), new UniqueTagList()), + new Event(new Name("Get Rich Seminar"), new DateTime("11-17 0000"), new DateTime("11-17 0210"), new UniqueTagList()), + new Event(new Name("Badminton"), new DateTime("01-03 1400"), new DateTime("12-02 1700"), new UniqueTagList()), + }; + } catch (IllegalValueException e) { + assert false; + //not possible + return null; + } + } + + private static Deadline[] getSampleDeadlineData() { + try { + return new Deadline[]{ + new Deadline(new Name("Complete ST4231 Homework"), new DateTime ("10-20 2300"), new UniqueTagList()), + new Deadline(new Name("Feed Elizabeth the 3rd"), new DateTime ("08-08 0808"), new UniqueTagList()), + new Deadline(new Name("Buy materials for christmas party!"), new DateTime ("12-24 1200"), new UniqueTagList()), + new Deadline(new Name("Make new year resolutions"), new DateTime ("12-31 2359"), new UniqueTagList()), + new Deadline(new Name("Study for Test"), new DateTime ("11-18 1300"), new UniqueTagList()), + new Deadline(new Name("Buy food for Zen"), new DateTime ("01-01-2017 0000"), new UniqueTagList()), + new Deadline(new Name("Buy present for girlfriend"), new DateTime ("03-05-2017 0500"), new UniqueTagList()), + new Deadline(new Name("Complete Hearthstone missions"), new DateTime ("06-10 1940"), new UniqueTagList()), + new Deadline(new Name("Reply lecturer emails"), new DateTime ("10-30-2016 2359"), new UniqueTagList()) + }; + } catch (IllegalValueException e) { + assert false; + //not possible + return null; + } + } + + public static final Tag[] sampleTagData = getSampleTagData(); + + private static Tag[] getSampleTagData() { + try { + return new Tag[]{ + new Tag("relatives"), + new Tag("friends") + }; + } catch (IllegalValueException e) { + assert false; + return null; + //not possible + } + } + + public static List generateSampleTaskData() { + return Arrays.asList(sampleFloatingTaskData); + } + + public static List generateSampleDeadlineData() { + return Arrays.asList(sampleDeadlineData); + } + + public static List generateSampleEventData() { + return Arrays.asList(sampleEventData); + } + + /** + * Appends the file name to the sandbox folder path. + * Creates the sandbox folder if it doesn't exist. + * @param fileName + * @return + */ + public static String getFilePathInSandboxFolder(String fileName) { + try { + FileUtil.createDirs(new File(SANDBOX_FOLDER)); + } catch (IOException e) { + throw new RuntimeException(e); + } + return SANDBOX_FOLDER + fileName; + } + + public static void createDataFileWithSampleData(String filePath) { + createDataFileWithData(generateSampleStoragemalitio(), filePath); + } + + public static void createDataFileWithData(T data, String filePath) { + try { + File saveFileForTesting = new File(filePath); + FileUtil.createIfMissing(saveFileForTesting); + XmlUtil.saveDataToFile(saveFileForTesting, data); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String... s) { + createDataFileWithSampleData(TestApp.SAVE_LOCATION_FOR_TESTING); + } + + public static Malitio generateEmptymalitio() { + return new Malitio(new UniqueFloatingTaskList(), new UniqueDeadlineList(), + new UniqueEventList(), new UniqueTagList()); + } + + public static XmlSerializableMalitio generateSampleStoragemalitio() { + return new XmlSerializableMalitio(generateEmptymalitio()); + } + + /** + * Tweaks the {@code keyCodeCombination} to resolve the {@code KeyCode.SHORTCUT} to their + * respective platform-specific keycodes + */ + public static KeyCode[] scrub(KeyCodeCombination keyCodeCombination) { + List keys = new ArrayList<>(); + if (keyCodeCombination.getAlt() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.ALT); + } + if (keyCodeCombination.getShift() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.SHIFT); + } + if (keyCodeCombination.getMeta() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.META); + } + if (keyCodeCombination.getControl() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.CONTROL); + } + keys.add(keyCodeCombination.getCode()); + return keys.toArray(new KeyCode[]{}); + } + + public static boolean isHeadlessEnvironment() { + String headlessProperty = System.getProperty("testfx.headless"); + return headlessProperty != null && headlessProperty.equals("true"); + } + + public static void captureScreenShot(String fileName) { + File file = GuiTest.captureScreenshot(); + try { + Files.copy(file, new File(fileName + ".png")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String descOnFail(Object... comparedObjects) { + return "Comparison failed \n" + + Arrays.asList(comparedObjects).stream() + .map(Object::toString) + .collect(Collectors.joining("\n")); + } + + public static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException{ + field.setAccessible(true); + // remove final modifier from field + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + // ~Modifier.FINAL is used to remove the final modifier from field so that its value is no longer + // final and can be changed + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + field.set(null, newValue); + } + + public static void initRuntime() throws TimeoutException { + FxToolkit.registerPrimaryStage(); + FxToolkit.hideStage(); + } + + public static void tearDownRuntime() throws Exception { + FxToolkit.cleanupStages(); + } + + /** + * Gets private method of a class + * Invoke the method using method.invoke(objectInstance, params...) + * + * Caveat: only find method declared in the current Class, not inherited from supertypes + */ + public static Method getPrivateMethod(Class objectClass, String methodName) throws NoSuchMethodException { + Method method = objectClass.getDeclaredMethod(methodName); + method.setAccessible(true); + return method; + } + + public static void renameFile(File file, String newFileName) { + try { + Files.copy(file, new File(newFileName)); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + + /** + * Gets mid point of a node relative to the screen. + * @param node + * @return + */ + public static Point2D getScreenMidPoint(Node node) { + double x = getScreenPos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; + double y = getScreenPos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; + return new Point2D(x,y); + } + + /** + * Gets mid point of a node relative to its scene. + * @param node + * @return + */ + public static Point2D getSceneMidPoint(Node node) { + double x = getScenePos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; + double y = getScenePos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; + return new Point2D(x,y); + } + + /** + * Gets the bound of the node relative to the parent scene. + * @param node + * @return + */ + public static Bounds getScenePos(Node node) { + return node.localToScene(node.getBoundsInLocal()); + } + + public static Bounds getScreenPos(Node node) { + return node.localToScreen(node.getBoundsInLocal()); + } + + public static double getSceneMaxX(Scene scene) { + return scene.getX() + scene.getWidth(); + } + + public static double getSceneMaxY(Scene scene) { + return scene.getX() + scene.getHeight(); + } + + public static Object getLastElement(List list) { + return list.get(list.size() - 1); + } + + /** + * Removes a subset from the list of tasks. + * @param tasks The list of tasks + * @param tasksToRemove The subset of tasks. + * @return The modified tasks after removal of the subset from tasks. + */ + public static TestFloatingTask[] removeTasksFromList(final TestFloatingTask[] tasks, TestFloatingTask... tasksToRemove) { + List listOfTasks = asList(tasks); + listOfTasks.removeAll(asList(tasksToRemove)); + return listOfTasks.toArray(new TestFloatingTask[listOfTasks.size()]); + } + + + public static TestDeadline[] removeTasksFromList(final TestDeadline[] tasks, TestDeadline... tasksToRemove) { + List listOfTasks = asList(tasks); + listOfTasks.removeAll(asList(tasksToRemove)); + return listOfTasks.toArray(new TestDeadline[listOfTasks.size()]); + } + + public static TestEvent[] removeTasksFromList(final TestEvent[] tasks, TestEvent... tasksToRemove) { + List listOfTasks = asList(tasks); + listOfTasks.removeAll(asList(tasksToRemove)); + return listOfTasks.toArray(new TestEvent[listOfTasks.size()]); + } + + /** + * Returns a copy of the list with the task at specified index removed. + * @param list original list to copy from + * @param targetIndexInOneIndexedFormat e.g. if the first element to be removed, 1 should be given as index. + */ + public static TestFloatingTask[] removeTasksFromList(final TestFloatingTask[] list, int targetIndexInOneIndexedFormat) { + return removeTasksFromList(list, list[targetIndexInOneIndexedFormat-1]); + } + + /** + * Replaces tasks[i] with a task. + * @param tasks The array of tasks. + * @param task The replacement task + * @param index The index of the task to be replaced. + * @return + */ + public static TestFloatingTask[] replaceTaskFromList(TestFloatingTask[] tasks, TestFloatingTask task, int index) { + tasks[index] = task; + return tasks; + } + + /** + * Appends tasks to the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. + */ + public static TestFloatingTask[] addTasksToList(final TestFloatingTask[] tasks, TestFloatingTask... tasksToAdd) { + List listOfTasks = asList(tasks); + listOfTasks.addAll(asList(tasksToAdd)); + return listOfTasks.toArray(new TestFloatingTask[listOfTasks.size()]); + } + + public static TestDeadline[] addTasksToList(final TestDeadline[] deadlines, TestDeadline... deadlinesToAdd) { + List listOfDeadlines = asList(deadlines); + listOfDeadlines.addAll(asList(deadlinesToAdd)); + Collections.sort(listOfDeadlines, new Comparator() { + public int compare(TestDeadline d1, TestDeadline d2) { + if (d1.getDue() == null || d2.getDue() == null) + return 0; + return d1.getDue().compareTo(d2.getDue()); + } + }); + return listOfDeadlines.toArray(new TestDeadline[listOfDeadlines.size()]); + } + + public static TestEvent[] addTasksToList(final TestEvent[] events, TestEvent... eventsToAdd) { + List listOfEvents = asList(events); + listOfEvents.addAll(asList(eventsToAdd)); + Collections.sort(listOfEvents, new Comparator() { + public int compare(TestEvent e1, TestEvent e2) { + if (e1.getStart() == null || e2.getStart() == null) + return 0; + return e1.getStart().compareTo(e2.getStart()); + } + }); + return listOfEvents.toArray(new TestEvent[listOfEvents.size()]); + } + + private static List asList(T[] objs) { + List list = new ArrayList<>(); + for(T obj : objs) { + list.add(obj); + } + return list; + } + + public static boolean compareCardAndTask(FloatingTaskCardHandle card, ReadOnlyFloatingTask task) { + return card.isSameTask(task); + } + + public static boolean compareCardAndTask(DeadlineCardHandle card, ReadOnlyDeadline task) { + return card.isSameDeadline(task); + } + + public static boolean compareCardAndTask(EventCardHandle card, ReadOnlyEvent task) { + return card.isSameTask(task); + } + + public static Tag[] getTagList(String tags) { + + if (tags.equals("")) { + return new Tag[]{}; + } + + final String[] split = tags.split(", "); + + final List collect = Arrays.asList(split).stream().map(e -> { + try { + return new Tag(e.replaceFirst("Tag: ", "")); + } catch (IllegalValueException e1) { + //not possible + assert false; + return null; + } + }).collect(Collectors.toList()); + + return collect.toArray(new Tag[split.length]); + } + +} diff --git a/src/test/java/seedu/malitio/testutil/TypicalTestTasks.java b/src/test/java/seedu/malitio/testutil/TypicalTestTasks.java new file mode 100644 index 000000000000..b31efbd06067 --- /dev/null +++ b/src/test/java/seedu/malitio/testutil/TypicalTestTasks.java @@ -0,0 +1,110 @@ +package seedu.malitio.testutil; + +import seedu.malitio.commons.exceptions.DuplicateDataException; +import seedu.malitio.commons.exceptions.IllegalValueException; +import seedu.malitio.model.Malitio; +import seedu.malitio.model.task.*; + +/** + * + */ +public class TypicalTestTasks { + + public static TestFloatingTask floatingTask1, floatingTask2, floatingTask3, floatingTask4, floatingTask5, + manualFloatingTask1, manualFloatingTask2, editedFloatingTask1, editedFloatingTask2, editedFloatingTask3; + public static TestDeadline deadline1, deadline2, deadline3, deadline4, deadline5, manualDeadline1, + manualDeadline2, editedDeadline1, editedDeadline2, editedDeadline3, editedDeadline4; + public static TestEvent event1, event2, event3, event4, event5, event6, manualEvent1, manualEvent2, manualEvent3, + editedEvent1, editedEvent2, editedEvent3, editedEvent4, editedEvent5; + + public TypicalTestTasks() { + try { + floatingTask1 = new FloatingTaskBuilder().withName("Adjust meter").withTags("careful").build(); + floatingTask2 = new FloatingTaskBuilder().withName("Bring along notes").withTags("pen", "cs2103").build(); + floatingTask3 = new FloatingTaskBuilder().withName("Tell your world").build(); + floatingTask4 = new FloatingTaskBuilder().withName("Download Promise Song").build(); + floatingTask5 = new FloatingTaskBuilder().withName("Cendrillion").withTags("vocaloid").build(); + deadline1 = new DeadlineBuilder().withName("Cut hair").dueOn("10-12 2000").build(); + deadline2 = new DeadlineBuilder().withName("Do some sit-up").dueOn("10-31 2359").build(); + deadline3 = new DeadlineBuilder().withName("Buy stuff").dueOn("11-01 1745").withTags("Pencil").build(); + deadline4 = new DeadlineBuilder().withName("Practice singing").dueOn("12-25 0000").withTags("Christmas", "Carols").build(); + deadline5 = new DeadlineBuilder().withName("Finish homework").dueOn("12-31 2300").withTags("help").build(); + event1 = new EventBuilder().withName("Eat with mom").start("01-10-2017 1800").end("01-10-2017 1855").withTags("yummy").build(); + event2 = new EventBuilder().withName("Forgive with forget").start("02-22-2017 1000").end("02-23-2017 1000").withTags("peace").build(); + event3 = new EventBuilder().withName("Go shopping").start("03-30-2017 0900").end("03-30-2017 2000").withTags("clothes").build(); + event4 = new EventBuilder().withName("Hopping").start("11-01-2017 0400").end("11-01-2017 0600").withTags("hello").build(); + event5 = new EventBuilder().withName("Christmas party").start("12-25-2017 0000").end("12-25-2017 2359").withTags("presents").build(); + event6 = new EventBuilder().withName("New year party").start("12-31-2017 0000").end("12-31-2017 2359").build(); + + //Manually added + manualFloatingTask1 = new FloatingTaskBuilder().withName("Spa relaxation").build(); + manualFloatingTask2 = new FloatingTaskBuilder().withName("Play cards").build(); + manualDeadline1 = new DeadlineBuilder().withName("Prepare for interview").dueOn("01-20 0000").build(); + manualDeadline2 = new DeadlineBuilder().withName("Get watch fixed").dueOn("10-21 2359").build(); + manualEvent1 = new EventBuilder().withName("Boring Lecture").start("11-17 1100").end("11-17 1200").build(); + manualEvent2 = new EventBuilder().withName("Scary Interview").start("12-18 1300").end("12-18 1400").build(); + manualEvent3 = new EventBuilder().withName("Bungee Jumping").start("yesterday 1000").end("yesterday 1200").build(); + + //Editted Versions of Tasks + editedFloatingTask1 = new FloatingTaskBuilder().withName("how are you").withTags("careful").build(); + editedFloatingTask2 = new FloatingTaskBuilder().withName("Bring along notes").withTags("omg").build(); + editedFloatingTask3 = new FloatingTaskBuilder().withName("Tell Nobody").withTags("heello").build(); + editedDeadline1 = new DeadlineBuilder().withName("Cut more hair").dueOn("10-12 2000").build(); + editedDeadline2 = new DeadlineBuilder().withName("Do some sit-up").dueOn("22 dec 12am").build(); + editedDeadline3 = new DeadlineBuilder().withName("Buy stuff").dueOn("11-01 1745").withTags("Pineapple", "Pen").build(); + editedDeadline4 = new DeadlineBuilder().withName("I want to sleep").dueOn("25 Oct 11pm").withTags("damntired").build(); + editedEvent1 = new EventBuilder().withName("Eat with dad").start("01-10-2017 1800").end("01-10-2017 1855").withTags("yummy").build(); + editedEvent2 = new EventBuilder().withName("Forgive with forget").start("02-22-2017 1300").end("02-23-2017 1000").withTags("peace").build(); + editedEvent3 = new EventBuilder().withName("Go shopping").start("03-30-2017 0900").end("03-30-2017 2100").withTags("clothes").build(); + editedEvent4 = new EventBuilder().withName("Hopping").start("11-01-2017 0400").end("11-01-2017 0600").withTags("fun", "yahoo").build(); + editedEvent5 = new EventBuilder().withName("Outing").start("02-14-2017 1000").end("02-14-2017 2000").withTags("dressup").build(); + } catch (IllegalValueException e) { + e.printStackTrace(); + assert false : "not possible"; + } + } + + public static void loadMalitioWithSampleData(Malitio ab) { + try { + ab.addTask(new FloatingTask(floatingTask1)); + ab.addTask(new FloatingTask(floatingTask2)); + ab.addTask(new FloatingTask(floatingTask3)); + ab.addTask(new FloatingTask(floatingTask4)); + ab.addTask(new FloatingTask(floatingTask5)); + ab.addTask(new Deadline(deadline1)); + ab.addTask(new Deadline(deadline2)); + ab.addTask(new Deadline(deadline3)); + ab.addTask(new Deadline(deadline4)); + ab.addTask( new Deadline(deadline5)); + ab.addTask(new Event(event1)); + ab.addTask(new Event(event2)); + ab.addTask(new Event(event3)); + ab.addTask(new Event(event4)); + ab.addTask(new Event(event5)); + ab.addTask(new Event(event6)); + } catch (DuplicateDataException e) { + assert false : "not possible"; + } catch (IllegalValueException e) { + assert false : "not possible:"; + } + } + + public TestFloatingTask[] getTypicalFloatingTasks() { + return new TestFloatingTask[]{floatingTask1, floatingTask2, floatingTask3, floatingTask4, floatingTask5}; + } + + public TestDeadline[] getTypicalDeadlines() { + return new TestDeadline[]{deadline1, deadline2, deadline3, deadline4, deadline5}; + } + + public TestEvent[] getTypicalEvents() { + return new TestEvent[]{event1, event2, event3, event4, event5, event6}; + } + + + public Malitio getTypicalMalitio() { + Malitio ab = new Malitio(); + loadMalitioWithSampleData(ab); + return ab; + } +}