diff --git a/.project b/.project
index 18f57e9ae6ac..9a3c79b5d72f 100644
--- a/.project
+++ b/.project
@@ -1,7 +1,7 @@
- addressbook-level4
- Project addressbook-level4 created by Buildship.
+ main
+ Project main created by Buildship.
@@ -26,24 +26,4 @@
org.eclipse.jdt.core.javanaturenet.sf.eclipsecs.core.CheckstyleNature
-
-
- 1476898072165
-
- 26
-
- org.eclipse.ui.ide.multiFilter
- 1.0-projectRelativePath-matches-false-false-build
-
-
-
- 1476898072188
-
- 26
-
- org.eclipse.ui.ide.multiFilter
- 1.0-projectRelativePath-matches-false-false-.gradle
-
-
-
diff --git a/.simplecov b/.simplecov
new file mode 100644
index 000000000000..f01404882382
--- /dev/null
+++ b/.simplecov
@@ -0,0 +1,7 @@
+require 'simplecov'
+require 'coveralls'
+
+SimpleCov.formatter = Coveralls::SimpleCov::Formatter
+SimpleCov.start do
+ add_filter 'collated/'
+end
diff --git a/Collate-TUI.jar b/Collate-TUI.jar
new file mode 100644
index 000000000000..2b9e032106dd
Binary files /dev/null and b/Collate-TUI.jar differ
diff --git a/README.md b/README.md
index b20684a1eac0..e492ced55ae9 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,14 @@
-# Address Book (Level 4)
+# Task Manager
+
+[](https://travis-ci.org/CS2103JAN2017-T11-B3/main)
+[](https://ci.appveyor.com/project/tylerrocha/main/branch/master)
+[](https://coveralls.io/github/CS2103JAN2017-T11-B3/main?branch=master)
+[](https://www.codacy.com/app/tylerrocha/main?utm_source=github.com&utm_medium=referral&utm_content=CS2103JAN2017-T11-B3/main&utm_campaign=Badge_Grade)
-[](https://travis-ci.org/se-edu/addressbook-level4)
-[](https://ci.appveyor.com/project/damithc/addressbook-level4)
-[](https://coveralls.io/github/se-edu/addressbook-level4?branch=master)
-[](https://www.codacy.com/app/damith/addressbook-level4?utm_source=github.com&utm_medium=referral&utm_content=se-edu/addressbook-level4&utm_campaign=Badge_Grade)
-* This is a desktop Address Book 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.
-* It is **written in OOP fashion**. It provides a **reasonably well-written** code example that is
- **significantly bigger** (around 6 KLoC)than what students usually write in beginner-level SE modules.
-* What's different from [level 3](https://github.com/se-edu/addressbook-level3):
- * A more sophisticated GUI that includes a list panel and an in-built Browser.
- * More test cases, including automated GUI testing.
- * Support for *Build Automation* using Gradle and for *Continuous Integration* using Travis CI.
+* This is a desktop Task Manager application created for CS2103 Software Engineering at the National University of Singapore. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface).
#### Site Map
@@ -29,8 +21,9 @@
#### Acknowledgements
-* Some parts of this sample application were inspired by the excellent
+* Some parts of this sample application were inspired by this
[Java FX tutorial](http://code.makery.ch/library/javafx-8-tutorial/) by *Marco Jakob*.
+* This project was built off an address book application by SE-EDU and can be found at https://github.com/se-edu/
#### Licence : [MIT](LICENSE)
diff --git a/_config.yml b/_config.yml
index 277f1f2c510d..72d781d70d10 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1 +1 @@
-theme: jekyll-theme-cayman
+theme: jekyll-theme-tactile
diff --git a/blooper b/blooper
new file mode 100644
index 000000000000..93f65208e5e4
--- /dev/null
+++ b/blooper
@@ -0,0 +1,24 @@
+
+
+
+ Say so long to Fiona Kunz
+ 1
+ false
+ 0
+ owesMoney
+ friends
+
+ false
+
+ 02/03/2100
+ 2100-03-02T00:00:00+08:00
+
+
+ 01/02/2017
+ 2017-02-01T00:00:00+08:00
+
+
+
+ owesMoney
+ friends
+
diff --git a/build.gradle b/build.gradle
index d5a0c00943ee..298d1d3a0622 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,7 +12,7 @@ plugins {
}
// Specifies the entry point of the application
-mainClassName = 'seedu.address.MainApp'
+mainClassName = 'seedu.task.MainApp'
allprojects {
apply plugin: 'idea'
@@ -39,7 +39,7 @@ allprojects {
jacksonVersion = '2.7.0'
jacksonDataTypeVersion = '2.7.4'
junitVersion = '4.12'
- testFxVersion = '4.0.+'
+ testFxVersion = '4.0.5-alpha'
monocleVersion = '1.8.0_20'
checkstyleVersion = '7.1.2'
diff --git a/collate b/collate
new file mode 100755
index 000000000000..9c4bf6f0e1d0
--- /dev/null
+++ b/collate
@@ -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 unused to collated/unused include java, fxml, css
diff --git a/collated/main/A0113795Y.md b/collated/main/A0113795Y.md
new file mode 100644
index 000000000000..ffab2a27c8bf
--- /dev/null
+++ b/collated/main/A0113795Y.md
@@ -0,0 +1,446 @@
+# A0113795Y
+###### /java/seedu/task/logic/commands/CompleteCommand.java
+``` java
+package seedu.task.logic.commands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.core.UnmodifiableObservableList;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.logic.parser.ParserUtil;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.EditTaskDescriptor;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.model.task.UniqueTaskList;
+
+/**
+ * Change the task status to completed
+ */
+
+public class CompleteCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(CompleteCommand.class);
+ public static final String COMMAND_WORD = "complete";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Mark the task identified by the index number."
+ + "used in the last task lisitng as completed.\n"
+ + "Parameter: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 2";
+
+ public static final String MESSAGE_COMPLETE_TASK_SUCCESS = "Completed task: %1$s";
+ public static final String MESSAGE_DUPLICATE_TAG = "This tag already exists in the tag list";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
+ public static final String MESSAGE_TAG_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_NULL_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+
+ public final int targetIndex;
+ public final EditTaskDescriptor completeTaskDescriptor;
+
+ public CompleteCommand(int targetIndex) {
+ assert targetIndex > 0;
+
+ this.targetIndex = targetIndex - 1;
+ this.completeTaskDescriptor = new EditTaskDescriptor();
+
+ List list = new ArrayList<>();
+ list.add("complete");
+ try {
+ this.completeTaskDescriptor.setTags(parseTagsForComplete(ParserUtil.toSet(Optional.of(list))));
+ } catch (IllegalValueException e) {
+ e.printStackTrace();
+ }
+ }
+```
+###### /java/seedu/task/logic/commands/CompleteCommand.java
+``` java
+ /**
+ * Creates and returns a {@code Task} with the details of {@code taskToComplete}
+ * edited with {@code editTaskDescriptor}.
+ */
+ private static Task createCompletedTask(ReadOnlyTask taskToComplete,
+ EditTaskDescriptor editTaskDescriptor) throws CommandException {
+ assert taskToComplete != null;
+
+ Description updatedDescription = editTaskDescriptor.getDescription().orElseGet(taskToComplete::getDescription);
+ Priority updatedPriority = editTaskDescriptor.getPriority().orElseGet(taskToComplete::getPriority);
+ Timing updatedStartDate = editTaskDescriptor.getStartTiming().orElseGet(taskToComplete::getStartTiming);
+ Timing updatedEndDate = editTaskDescriptor.getEndTiming().orElseGet(taskToComplete::getEndTiming);
+ UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToComplete::getTags);
+ boolean updatedRecurring = editTaskDescriptor.isRecurring().orElseGet(taskToComplete::isRecurring);
+ RecurringFrequency updatedFrequency = editTaskDescriptor.getFrequency().orElseGet(taskToComplete::getFrequency);
+
+ updatedStartDate.setTiming(updatedStartDate.toString());
+ updatedEndDate.setTiming(updatedEndDate.toString());
+
+ Task ret;
+ try {
+ ret = new Task(updatedDescription, updatedPriority, updatedStartDate,
+ updatedEndDate, updatedTags, updatedRecurring, updatedFrequency);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ ret.setComplete();
+ return ret;
+ }
+
+ /**
+ * Parses {@code Collection tags} into an {@code Optional} if {@code tags} is non-empty.
+ * If {@code tags} contain only one element which is an empty string, it will be parsed into a
+ * {@code Optional} containing zero tags.
+ */
+ private Optional parseTagsForComplete(Collection tags) throws IllegalValueException {
+ Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
+ return Optional.of(ParserUtil.parseTags(tagSet));
+ }
+}
+```
+###### /java/seedu/task/logic/commands/PrioritizeCommand.java
+``` java
+package seedu.task.logic.commands;
+
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.core.UnmodifiableObservableList;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.EditTaskDescriptor;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.model.task.UniqueTaskList;
+
+public class PrioritizeCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(PrioritizeCommand.class);
+ public static final String COMMAND_WORD = "prioritize";
+ public static final String MESSAGE_PRIORITY_CONSTRAINTS = "Task priority should be between 1-3";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Change the priority of the task identified "
+ + "by the index number used in the last task lisitng as completed.\n"
+ + "Parameter: INDEX (must be a positive integer) NEW_PRIORITY_LEVEL (integer from 1 to 3)\n"
+ + "Example: " + COMMAND_WORD + " 2" + " 1";
+
+ public static final String MESSAGE_PRIORITIZE_TASK_SUCCESS = "Prioritized task: %1$s";
+ public static final String MESSAGE_DUPLICATE_TAG = "This tag already exists in the tag list";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
+ public static final String MESSAGE_TAG_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_NULL_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+
+ public final int targetIndex;
+ public final EditTaskDescriptor prioritizeTaskDescriptor;
+
+ public PrioritizeCommand(int targetIndex, Priority newPriority) {
+ assert targetIndex > 0;
+
+ this.targetIndex = targetIndex - 1;
+ this.prioritizeTaskDescriptor = new EditTaskDescriptor();
+ this.prioritizeTaskDescriptor.setPriority(Optional.of(newPriority));
+ }
+
+ @Override
+ public CommandResult execute() throws CommandException {
+
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ if (lastShownList.size() <= targetIndex) {
+ logger.info(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToComplete = lastShownList.get(targetIndex);
+ Task completedTask = createPrioritizedTask(taskToComplete, prioritizeTaskDescriptor);
+
+ try {
+ model.updateTask(targetIndex, completedTask);
+ } catch (UniqueTaskList.DuplicateTaskException dpe) {
+ logger.info(MESSAGE_DUPLICATE_TASK);
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ }
+
+ model.updateFilteredListToShowAll();
+ logger.info(String.format(MESSAGE_PRIORITIZE_TASK_SUCCESS, taskToComplete));
+ return new CommandResult(String.format(MESSAGE_PRIORITIZE_TASK_SUCCESS, taskToComplete));
+ }
+
+ /**
+ * Creates and returns a {@code Task} with the details of {@code taskToComplete}
+ * edited with {@code editTaskDescriptor}.
+ */
+ private static Task createPrioritizedTask(ReadOnlyTask taskToPrioritize,
+ EditTaskDescriptor editTaskDescriptor) throws CommandException {
+ assert taskToPrioritize != null;
+
+ Description updatedDescription = editTaskDescriptor.getDescription()
+ .orElseGet(taskToPrioritize::getDescription);
+ Priority updatedPriority = editTaskDescriptor.getPriority().orElseGet(taskToPrioritize::getPriority);
+ Timing updatedStartDate = editTaskDescriptor.getStartTiming().orElseGet(taskToPrioritize::getStartTiming);
+ Timing updatedEndDate = editTaskDescriptor.getEndTiming().orElseGet(taskToPrioritize::getEndTiming);
+ UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToPrioritize::getTags);
+ boolean updatedRecurring = editTaskDescriptor.isRecurring().orElseGet(taskToPrioritize::isRecurring);
+ RecurringFrequency updatedFrequency = editTaskDescriptor.getFrequency()
+ .orElseGet(taskToPrioritize::getFrequency);
+
+ try {
+ return new Task(updatedDescription, updatedPriority, updatedStartDate,
+ updatedEndDate, updatedTags, updatedRecurring, updatedFrequency);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ }
+}
+```
+###### /java/seedu/task/logic/commands/RedoCommand.java
+``` java
+package seedu.task.logic.commands;
+
+import java.util.EmptyStackException;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.logic.commands.exceptions.CommandException;
+
+/**
+ * Redo the previous change undone to the Task Manager
+ */
+public class RedoCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(RedoCommand.class);
+ public static final String COMMAND_WORD = "redo";
+ public static final String MESSAGE_SUCCESS = "Preivous undo restored.";
+ public static final String MESSAGE_INVALID_REDO_COMMAND = "Nothing to redo!";
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ try {
+ model.redo();
+ } catch (EmptyStackException ese) {
+ logger.info(MESSAGE_INVALID_REDO_COMMAND);
+ throw new CommandException(MESSAGE_INVALID_REDO_COMMAND);
+ }
+ logger.info(MESSAGE_SUCCESS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
+```
+###### /java/seedu/task/logic/commands/UndoCommand.java
+``` java
+package seedu.task.logic.commands;
+
+import java.util.EmptyStackException;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.logic.commands.exceptions.CommandException;
+
+/**
+ * Undo the previous change to the Task Manager
+ */
+public class UndoCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(UndoCommand.class);
+ public static final String COMMAND_WORD = "undo";
+ public static final String MESSAGE_SUCCESS = "Previous change is undone";
+ public static final String MESSAGE_INVALID_UNDO_COMMAND = "Nothing to undo!";
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ try {
+ model.undo();
+ } catch (EmptyStackException ese) {
+ logger.info(MESSAGE_INVALID_UNDO_COMMAND);
+ throw new CommandException(MESSAGE_INVALID_UNDO_COMMAND);
+ }
+ logger.info(MESSAGE_SUCCESS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
+```
+###### /java/seedu/task/logic/parser/CompleteCommandParser.java
+``` java
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Optional;
+
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.CompleteCommand;
+import seedu.task.logic.commands.IncorrectCommand;
+
+/**
+ * Parses input arguments and creates a new DeleteCommand object
+ */
+public class CompleteCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteCommand
+ * and returns an DeleteCommand object for execution.
+ */
+ public Command parse(String args) {
+
+ Optional index = ParserUtil.parseIndex(args);
+ if (!index.isPresent()) {
+ return new IncorrectCommand(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE));
+ }
+ return new CompleteCommand(index.get());
+ }
+}
+```
+###### /java/seedu/task/logic/parser/PrioritizeCommandParser.java
+``` java
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.task.model.task.Priority.MESSAGE_PRIORITY_CONSTRAINTS;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.PrioritizeCommand;
+import seedu.task.model.task.Priority;
+
+public class PrioritizeCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the PrioritizeCommand
+ * and returns an EditCommand object for execution.
+ */
+ public Command parse(String args) throws NoSuchElementException {
+ assert args != null;
+ ArgumentTokenizer argsTokenizer =
+ new ArgumentTokenizer();
+ argsTokenizer.tokenize(args);
+ List> preambleFields = ParserUtil.splitPreamble(argsTokenizer.getPreamble().orElse(""), 2);
+ Optional newValue = preambleFields.get(1);
+
+ Optional index = preambleFields.get(0).flatMap(ParserUtil::parseIndex);
+ if (!index.isPresent()) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, PrioritizeCommand.MESSAGE_USAGE));
+ }
+
+ try {
+ return new PrioritizeCommand(index.get(), new Priority(newValue.get()));
+ } catch (NoSuchElementException nsee) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, PrioritizeCommand.MESSAGE_USAGE));
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(String.format(MESSAGE_PRIORITY_CONSTRAINTS));
+ }
+ }
+}
+```
+###### /java/seedu/task/model/ModelManager.java
+``` java
+ @Override
+ public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException {
+ TaskList update = new TaskList(this.taskList);
+ undoStack.push(update);
+ while (!redoStack.empty()) {
+ redoStack.pop();
+ }
+ this.taskList.removeTask(target);
+ indicateTaskListChanged();
+ }
+
+ @Override
+ public synchronized void deleteThisTask(ReadOnlyTask targetToDelete,
+ Task targetToAdd) throws TaskNotFoundException, DuplicateTaskException {
+ this.taskList.removeTask(targetToDelete);
+ this.taskList.addTask(targetToAdd);
+ TaskList update = new TaskList(this.taskList);
+ undoStack.push(update);
+ while (!redoStack.empty()) {
+ redoStack.pop();
+ }
+ this.taskList.removeTask(targetToAdd);
+ this.taskList.addTask((Task) targetToDelete);
+ updateFilteredListToShowAll();
+ indicateTaskListChanged();
+ }
+
+ @Override
+ public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskException {
+ TaskList update = new TaskList(this.taskList);
+ undoStack.push(update);
+ while (!redoStack.empty()) {
+ redoStack.pop();
+ }
+ this.taskList.addTask(task);
+ updateFilteredListToShowAll();
+ indicateTaskListChanged();
+ }
+
+ @Override
+ public void updateTask(int filteredPersonListIndex, ReadOnlyTask editedTask)
+ throws UniqueTaskList.DuplicateTaskException {
+ assert editedTask != null;
+
+ int addressBookIndex = filteredTasks.getSourceIndex(filteredPersonListIndex);
+ TaskList update = new TaskList(this.taskList);
+ undoStack.push(update);
+ while (!redoStack.empty()) {
+ redoStack.pop();
+ }
+ this.taskList.updateTask(addressBookIndex, editedTask);
+ indicateTaskListChanged();
+ }
+
+ @Override
+ public void updateThisTask(int filteredPersonListIndex, ReadOnlyTask editedTask,
+ Task newTaskToAdd) throws UniqueTaskList.DuplicateTaskException {
+ assert editedTask != null;
+
+ int addressBookIndex = filteredTasks.getSourceIndex(filteredPersonListIndex);
+ TaskList update = new TaskList(this.taskList);
+ undoStack.push(update);
+ while (!redoStack.empty()) {
+ redoStack.pop();
+ }
+ this.taskList.updateTask(addressBookIndex, editedTask);
+ this.taskList.addTask(newTaskToAdd);
+ }
+
+ @Override
+ public void undo() {
+ TaskList temp = undoStack.peek();
+ redoStack.push(new TaskList(this.taskList));
+ this.taskList.resetData(temp);
+ undoStack.pop();
+ }
+
+ @Override
+ public void redo() {
+ TaskList temp = redoStack.peek();
+ undoStack.push(new TaskList(this.taskList));
+ this.taskList.resetData(temp);
+ redoStack.pop();
+ }
+
+ @Override
+ public Stack getUndoStack() {
+ return this.undoStack;
+ }
+```
diff --git a/collated/main/A0163559U.md b/collated/main/A0163559U.md
new file mode 100644
index 000000000000..2678405f7fb6
--- /dev/null
+++ b/collated/main/A0163559U.md
@@ -0,0 +1,495 @@
+# A0163559U
+###### /java/seedu/task/commons/util/FileUtil.java
+``` java
+ /**
+ * Compares the contents of two files.
+ * @param f1 file 1
+ * @param f2 file 2
+ * @return true if file contents are identical
+ * @throws IOException
+ */
+ public static boolean isFileContentSame(File f1, File f2) throws IOException {
+ String fileAsString1 = readFromFile(f1);
+ String fileAsString2 = readFromFile(f2);
+ System.out.println(fileAsString1);
+ System.out.println(fileAsString2);
+ return fileAsString1.equals(fileAsString2);
+ }
+```
+###### /java/seedu/task/logic/commands/Command.java
+``` java
+ public void setConfig(Config config) {
+ this.config = config;
+ }
+
+ public void setStorage(Storage storage) {
+ this.storage = storage;
+ }
+```
+###### /java/seedu/task/logic/commands/LoadCommand.java
+``` java
+package seedu.task.logic.commands;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.DataConversionException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.ReadOnlyTaskList;
+
+/**
+ * Loads task data from the specified directory and file.
+ */
+public class LoadCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(LoadCommand.class);
+
+ public static final String COMMAND_WORD = "load";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Loads all tasks from specified directory and file name. "
+ + "Parameters: LOAD_LOCATION\n"
+ + "Example: " + COMMAND_WORD
+ + " /Users/username/Documents/TaskManager/taskmanager.xml";
+
+ public static final String MESSAGE_SUCCESS = "Tasks loaded from location: %1$s";
+ public static final String MESSAGE_INVALID_LOAD_LOCATION = "This load location is invalid: %1$s";
+ public static final String MESSAGE_NULL_LOAD_LOCATION = "A load location must be specified.";
+ public static final String MESSAGE_DIRECTORY_LOAD_LOCATION = "A load location must also include the file name.";
+ public static final String MESSAGE_LOAD_IO_EXCEPTION = "Failed to load file in location: %1$s";
+
+ private final File toLoad;
+ /**
+ * Creates a LoadCommand using raw values.
+ *
+ * @throws IllegalValueException if the load location is invalid
+ * @throws IOException
+ */
+ public LoadCommand(String fileAsString) throws IllegalValueException {
+ if (fileAsString == null || fileAsString.equals("")) {
+ throw new IllegalValueException(MESSAGE_NULL_LOAD_LOCATION);
+ }
+
+ this.toLoad = new File(fileAsString.trim());
+
+ if (!toLoad.exists()) {
+ throw new IllegalValueException(String.format(MESSAGE_INVALID_LOAD_LOCATION, fileAsString));
+ }
+
+ if (toLoad.isDirectory()) {
+ throw new IllegalValueException(MESSAGE_DIRECTORY_LOAD_LOCATION);
+ }
+
+ assert toLoad.exists();
+
+ }
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ assert config != null;
+ logger.info("Executing load command with " + toLoad.toString());
+
+ try {
+ Optional newTaskList = storage.loadTaskListFromNewLocation(toLoad);
+ if (newTaskList.isPresent()) {
+ model.resetData(newTaskList.get());
+ }
+ } catch (FileNotFoundException | DataConversionException e1) {
+ logger.warning("Failed to execute load.");
+ throw new CommandException(MESSAGE_LOAD_IO_EXCEPTION);
+ }
+
+ config.setTaskManagerFilePath(toLoad.toString());
+
+ try {
+ ConfigUtil.saveConfig(config, Config.DEFAULT_CONFIG_FILE);
+ } catch (IOException e) {
+ logger.warning("Failed to execute load.");
+ throw new CommandException(String.format(MESSAGE_LOAD_IO_EXCEPTION, toLoad.toString()));
+ }
+ logger.info("Execute load succeeded");
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toLoad.toString()));
+
+ }
+
+}
+```
+###### /java/seedu/task/logic/commands/SaveCommand.java
+``` java
+package seedu.task.logic.commands;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.commons.util.FileUtil;
+import seedu.task.logic.commands.exceptions.CommandException;
+
+/**
+ * Saves task data in the specified directory and updates the default save directory.
+ */
+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_USAGE = COMMAND_WORD
+ + ": Saves all tasks in specified directory with specified file name. "
+ + "Parameters: SAVE_LOCATION\n"
+ + "Example: " + COMMAND_WORD
+ + " /Users/username/Documents/TaskManager/taskmanager.xml";
+
+ public static final String MESSAGE_SUCCESS = "Tasks saved in location: %1$s";
+ public static final String MESSAGE_INVALID_SAVE_LOCATION = "This save location is invalid: %1$s";
+ public static final String MESSAGE_NULL_SAVE_LOCATION = "A save location must be specified.\n" +
+ "Otherwise, saving occurs automatically in the current save location.";
+ public static final String MESSAGE_DIRECTORY_SAVE_LOCATION = "A save location must also include the file name.";
+ public static final String MESSAGE_SAVE_IO_EXCEPTION = "Failed to save file in location: %1$s";
+
+ private final File toSave;
+ /**
+ * Creates an SaveCommand using raw values.
+ *
+ * @throws IllegalValueException if the save location is invalid
+ * @throws IOException
+ */
+ public SaveCommand(String fileAsString) throws IllegalValueException {
+ if (fileAsString == null || fileAsString.equals("")) {
+ throw new IllegalValueException(MESSAGE_NULL_SAVE_LOCATION);
+ }
+ this.toSave = new File(fileAsString.trim());
+ if (toSave.isDirectory()) {
+ throw new IllegalValueException(MESSAGE_DIRECTORY_SAVE_LOCATION);
+ }
+ try {
+ createSaveFile();
+ } catch (IOException ioe) {
+ throw new IllegalValueException(String.format(MESSAGE_INVALID_SAVE_LOCATION, fileAsString));
+ }
+ assert toSave.exists();
+
+ }
+
+ private boolean createSaveFile() throws IOException {
+ boolean created = FileUtil.createFile(toSave);
+ if (!FileUtil.isFileExists(toSave) && !created) {
+ throw new IOException();
+ }
+ return created;
+ }
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ assert config != null;
+ logger.info("Executing load command with " + toSave.toString());
+
+ try {
+
+ storage.saveTaskListInNewLocation(model.getTaskList(), toSave);
+
+ //update configuration to reflect new save location
+ config.setTaskManagerFilePath(toSave.toString());
+
+ ConfigUtil.saveConfig(config, Config.DEFAULT_CONFIG_FILE);
+
+ } catch (IOException e) {
+ logger.warning("Failed to execute save.");
+
+ throw new CommandException(String.format(MESSAGE_SAVE_IO_EXCEPTION, toSave.toString()));
+ }
+ logger.info("Execute save succeeded");
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toSave.toString()));
+
+ }
+
+}
+```
+###### /java/seedu/task/logic/parser/LoadCommandParser.java
+``` java
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.NoSuchElementException;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.LoadCommand;
+
+/**
+ * Parses input arguments and creates a new LoadCommand object
+ */
+public class LoadCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the LoadCommand
+ * and returns a LoadCommand object for execution.
+ */
+ public Command parse(String args) {
+ if (args == null || args.trim().equals("")) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, LoadCommand.MESSAGE_USAGE));
+ }
+ String trimmedArgs = args.trim();
+ try {
+ //System.out.println("@@@Parsing load command: " + args);
+ return new LoadCommand(trimmedArgs);
+ } catch (NoSuchElementException nsee) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, LoadCommand.MESSAGE_USAGE));
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(ive.getMessage());
+ }
+ }
+
+}
+```
+###### /java/seedu/task/logic/parser/SaveCommandParser.java
+``` java
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.NoSuchElementException;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.SaveCommand;
+
+/**
+ * Parses input arguments and creates a new SaveCommand object
+ */
+public class SaveCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the SaveCommand
+ * and returns a SaveCommand object for execution.
+ */
+ public Command parse(String args) {
+ if (args == null || args.trim().equals("")) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SaveCommand.MESSAGE_USAGE));
+ }
+ String trimmedArgs = args.trim();
+ try {
+ return new SaveCommand(trimmedArgs);
+ } catch (NoSuchElementException nsee) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SaveCommand.MESSAGE_USAGE));
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(ive.getMessage());
+ }
+ }
+
+}
+```
+###### /java/seedu/task/model/task/Priority.java
+``` java
+ /**
+ * Results in Priority sorted in ascending order.
+ */
+ @Override
+ public int compareTo(Priority comparePriority) {
+ int thisValue = Integer.parseInt(this.value);
+ int otherValue = Integer.parseInt(comparePriority.value);
+ return thisValue - otherValue;
+ }
+```
+###### /java/seedu/task/model/task/Task.java
+``` java
+ /**
+ * Results in Tasks sorted by completed state, followed by priority, endTiming, startTiming
+ * and lastly by frequency.
+ * Note: If a and b are tasks and a.compareTo(b) == 0, that does not imply
+ * a.equals(b).
+ */
+ @Override
+ public int compareTo(Task compareTask) {
+ int compareToResult = 0;
+
+ if (this.isComplete() && compareTask.isComplete()) {
+ compareToResult = 0;
+ } else if (this.isComplete()) {
+ compareToResult = 1;
+ } else if (compareTask.isComplete()) {
+ compareToResult = -1;
+ }
+
+ if (compareToResult == 0) {
+ compareToResult = this.priority.compareTo(compareTask.priority);
+ }
+
+ if (compareToResult == 0) {
+ compareToResult = this.getEndTiming().compareTo(compareTask.getEndTiming());
+ }
+
+ if (compareToResult == 0) {
+ compareToResult = this.getStartTiming().compareTo(compareTask.getStartTiming());
+ }
+
+ if (compareToResult == 0) {
+ compareToResult = this.getDescription().compareTo(compareTask.getDescription());
+ }
+
+ return compareToResult;
+ }
+
+ public static Comparator taskComparator = new Comparator() {
+
+ @Override
+ public int compare(Task task1, Task task2) {
+ task1.getStartTiming().setTiming(task1.getStartTiming().toString());
+ task1.getEndTiming().setTiming(task1.getEndTiming().toString());
+ return task1.compareTo(task2);
+ }
+
+ };
+```
+###### /java/seedu/task/model/task/Timing.java
+``` java
+ @Override
+ public int compareTo(Timing compareTiming) {
+ int compareToResult = 0;
+
+ boolean thisTimingSpecified = this.value.equals(TIMING_NOT_SPECIFIED);
+ boolean otherTimingSpecified = compareTiming.value.equals(TIMING_NOT_SPECIFIED);
+
+ if (thisTimingSpecified && otherTimingSpecified) {
+ return compareToResult;
+ } else if (thisTimingSpecified) {
+ compareToResult = 1;
+ } else if (otherTimingSpecified) {
+ compareToResult = -1;
+ }
+
+ if (compareToResult == 0) {
+ Calendar thisCal = Calendar.getInstance();
+ Calendar otherCal = Calendar.getInstance();
+ thisCal.setTime(this.getTiming());
+ compareTiming.setTiming(compareTiming.toString());
+ otherCal.setTime(compareTiming.getTiming());
+ compareToResult = thisCal.compareTo(otherCal);
+ }
+
+ return compareToResult;
+ }
+```
+###### /java/seedu/task/storage/Storage.java
+``` java
+ /**
+ * Attempts to save current version of the Task Manager to new file location
+ * @param taskList is the Task Manager data to be saved
+ * @param saveFile is the save location
+ * @throws IOException if file operation fails
+ */
+ @Override
+ void saveTaskListInNewLocation(ReadOnlyTaskList taskList, File saveFile) throws IOException;
+
+ /**
+ * Attempts to load Task Manager data from specified file location
+ * @param loadFile is the file to load Task Manager data from
+ * @return
+ * @throws DataConversionException if data conversion fails
+ * @throws FileNotFoundException if the file is not found
+ */
+ @Override
+ Optional loadTaskListFromNewLocation(File loadFile)
+ throws FileNotFoundException, DataConversionException;
+
+```
+###### /java/seedu/task/storage/StorageManager.java
+``` java
+ @Override
+ /**
+ * Saves current state of task list in new location.
+ */
+ public void saveTaskListInNewLocation(ReadOnlyTaskList taskList, File newFile) throws IOException {
+ logger.fine("Attempting to copy task manager data to file: " + newFile.toString());
+ taskListStorage.saveTaskListInNewLocation(taskList, newFile);
+ }
+
+ @Override
+ /**
+ * Attempts to load a stored task list into the task manager.
+ */
+ public Optional loadTaskListFromNewLocation(File loadFile)
+ throws FileNotFoundException, DataConversionException {
+ logger.fine("Attempting to load task manager data from file: " + loadFile.toString());
+ return taskListStorage.loadTaskListFromNewLocation(loadFile);
+ }
+
+ /**
+ * Updates internal state data as storage support.
+ * @param file File to update state
+ */
+ public void updateXmlTaskListStorage(File file) {
+ XmlTaskListStorage xmlTaskListStorage = (XmlTaskListStorage) taskListStorage;
+ xmlTaskListStorage.updateState(file);;
+ }
+```
+###### /java/seedu/task/storage/TaskListStorage.java
+``` java
+ /**
+ * Copies the current save state of the Task Manager into a new location
+ * @param taskList is the state to be copied
+ * @param newFile is the new save location
+ * @throws IOException if file operations fail
+ */
+ void saveTaskListInNewLocation(ReadOnlyTaskList taskList, File newFile) throws IOException;
+
+ /**
+ * Loads saved state of Task Manager from specified location
+ * @param loadFile is the file to load state from
+ * @return new loaded task list, if successful
+ * @throws DataConversionException if data conversion fails
+ * @throws FileNotFoundException if file operation fails
+ */
+ Optional loadTaskListFromNewLocation(File loadFile)
+ throws FileNotFoundException, DataConversionException;
+```
+###### /java/seedu/task/storage/XmlTaskListStorage.java
+``` java
+ @Override
+ public void saveTaskListInNewLocation(ReadOnlyTaskList taskList, File newFile) throws IOException {
+ logger.info("Attempting to save taskList in file" + newFile);
+ saveTaskList(taskList, filePath);
+ try {
+ String taskData = FileUtil.readFromFile(savedFile);
+ System.out.println(taskData);
+ FileUtil.writeToFile(newFile, taskData);
+
+ } catch (FileAlreadyExistsException faee) {
+ logger.warning("FileAlreadyExistsException in saveTaskListInNewLocation");
+ return; //abort updating state
+ } catch (IOException ioe) {
+ logger.warning("IO Exception in saveTaskListInNewLocation");
+ return; //abort updating state
+ }
+ updateState(newFile);
+ }
+
+ public void updateState(File file) {
+ this.savedFile = file;
+ this.filePath = file.toString();
+ }
+
+ @Override
+ public Optional loadTaskListFromNewLocation(File loadFile)
+ throws FileNotFoundException, DataConversionException {
+ Optional newTaskList = readTaskList(loadFile.toString());
+ if (newTaskList.isPresent()) {
+ updateState(loadFile);
+ }
+ return newTaskList;
+ }
+```
diff --git a/collated/main/A0163935X.md b/collated/main/A0163935X.md
new file mode 100644
index 000000000000..5e0b4a9c3ade
--- /dev/null
+++ b/collated/main/A0163935X.md
@@ -0,0 +1,491 @@
+# A0163935X
+###### /java/seedu/task/ui/CalenderPanel.java
+``` java
+
+package seedu.task.ui;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListView;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.Region;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.util.FxViewUtil;
+import seedu.task.model.task.ReadOnlyTask;
+
+/**
+ * The Calender Panel of the App.
+ */
+// tutorial
+// https://www.youtube.com/watch?v=HiZ-glk9_LE&t=568s
+public class CalenderPanel extends UiPart {
+ private static final String FXML = "CalenderPanel.fxml";
+ private static final DateFormat YEAR = new SimpleDateFormat("yyyy");
+ private static final DateFormat MONTH = new SimpleDateFormat("MM");
+ private static final DateFormat DATE = new SimpleDateFormat("dd");
+ private static final DateFormat DAY = new SimpleDateFormat("EEEE");
+ private static final SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+ private HashMap dayHashMap = new HashMap();
+ private HashMap> taskListHashMap = new HashMap>();
+ // private static final DateTimeFormatter dtf =
+ // DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
+ // private HashMap dayHashMap;
+ // tutorial
+ // https://www.mkyong.com/java/java-how-to-get-current-date-time-date-and-calender/
+ @FXML
+ private TextField textfield;
+ @FXML
+ private Button button;
+ @FXML
+ private ListView listview1;
+ @FXML
+ private ListView listview2;
+ @FXML
+ private ListView listview3;
+ @FXML
+ private ListView listview4;
+ @FXML
+ private ListView listview5;
+ @FXML
+ private ListView listview6;
+ @FXML
+ private ListView listview7;
+ @FXML
+ private ListView listview8;
+ @FXML
+ private ListView listview9;
+ @FXML
+ private ListView listview10;
+ @FXML
+ private ListView listview11;
+ @FXML
+ private ListView listview12;
+ @FXML
+ private ListView listview13;
+ @FXML
+ private ListView listview14;
+ @FXML
+ private ListView listview15;
+ @FXML
+ private ListView listview16;
+ @FXML
+ private ListView listview17;
+ @FXML
+ private ListView listview18;
+ @FXML
+ private ListView listview19;
+ @FXML
+ private ListView listview20;
+ @FXML
+ private ListView listview21;
+ @FXML
+ private ListView listview22;
+ @FXML
+ private ListView listview23;
+ @FXML
+ private ListView listview24;
+ @FXML
+ private ListView listview25;
+ @FXML
+ private ListView listview26;
+ @FXML
+ private ListView listview27;
+ @FXML
+ private ListView listview28;
+ @FXML
+ private Label label1;
+
+ @FXML
+ private Label day1;
+ @FXML
+ private Label day2;
+ @FXML
+ private Label day3;
+ @FXML
+ private Label day4;
+ @FXML
+ private Label day5;
+ @FXML
+ private Label day6;
+ @FXML
+ private Label day7;
+ @FXML
+ private Label day8;
+ @FXML
+ private Label day9;
+ @FXML
+ private Label day10;
+ @FXML
+ private Label day11;
+ @FXML
+ private Label day12;
+ @FXML
+ private Label day13;
+ @FXML
+ private Label day14;
+ @FXML
+ private Label day15;
+ @FXML
+ private Label day16;
+ @FXML
+ private Label day17;
+ @FXML
+ private Label day18;
+ @FXML
+ private Label day19;
+ @FXML
+ private Label day20;
+ @FXML
+ private Label day21;
+ @FXML
+ private Label day22;
+ @FXML
+ private Label day23;
+ @FXML
+ private Label day24;
+ @FXML
+ private Label day25;
+ @FXML
+ private Label day26;
+ @FXML
+ private Label day27;
+ @FXML
+ private Label day28;
+ private static final Logger logger = LogsCenter.getLogger(CalenderPanel.class);
+ public CalenderPanel(AnchorPane calendertPlaceholder, ObservableList taskList, int dDate, int dMonth,
+ int dYear) {
+ super(FXML);
+ logger.info(" Initializing Calendar ");
+ FxViewUtil.applyAnchorBoundaryParameters(getRoot(), 0.0, 0.0, 0.0, 0.0);
+ /* ObservableList data = */ FXCollections.observableArrayList("hey", "you");
+ // label1.setText("v0.1");
+ setDate(dDate, dMonth, dYear);
+ setTasks(taskList);
+ // listview1.getItems().addAll("eat pizza", "go to gym");
+ calendertPlaceholder.getChildren().add(getRoot());
+ button.setOnAction(event -> {
+ String str = textfield.getText();
+ if (str != null) {
+ str = str.replaceAll("[^0-9]+", " ");
+ List monthAndDate = Arrays.asList(str.trim().split(" "));
+ int day = Integer.valueOf(monthAndDate.get(0));
+ int month = Integer.valueOf(monthAndDate.get(1));
+ int year = Integer.valueOf(monthAndDate.get(2));
+ cleanAllListView();
+ setDate(day, month, year);
+ setTasks(taskList);
+ }
+ });
+ }
+ private void cleanAllListView() {
+ listview1.getItems().clear();
+ listview2.getItems().clear();
+ listview3.getItems().clear();
+ listview4.getItems().clear();
+ listview5.getItems().clear();
+ listview6.getItems().clear();
+ listview7.getItems().clear();
+ listview8.getItems().clear();
+ listview9.getItems().clear();
+ listview10.getItems().clear();
+ listview11.getItems().clear();
+ listview12.getItems().clear();
+ listview13.getItems().clear();
+ listview14.getItems().clear();
+ listview15.getItems().clear();
+ listview16.getItems().clear();
+ listview17.getItems().clear();
+ listview18.getItems().clear();
+ listview19.getItems().clear();
+ listview20.getItems().clear();
+ listview21.getItems().clear();
+ listview22.getItems().clear();
+ listview23.getItems().clear();
+ listview24.getItems().clear();
+ listview25.getItems().clear();
+ listview26.getItems().clear();
+ listview27.getItems().clear();
+ listview28.getItems().clear();
+
+
+ }
+ private void initTaskListHashMap(HashMap> mytaskListHashMap) {
+ mytaskListHashMap.put("day1TaskList", listview1);
+ mytaskListHashMap.put("day2TaskList", listview2);
+ mytaskListHashMap.put("day3TaskList", listview3);
+ mytaskListHashMap.put("day4TaskList", listview4);
+ mytaskListHashMap.put("day5TaskList", listview5);
+ mytaskListHashMap.put("day6TaskList", listview6);
+ mytaskListHashMap.put("day7TaskList", listview7);
+ mytaskListHashMap.put("day8TaskList", listview8);
+ mytaskListHashMap.put("day9TaskList", listview9);
+ mytaskListHashMap.put("day10TaskList", listview10);
+ mytaskListHashMap.put("day11TaskList", listview11);
+ mytaskListHashMap.put("day12TaskList", listview12);
+ mytaskListHashMap.put("day13TaskList", listview13);
+ mytaskListHashMap.put("day14TaskList", listview14);
+ mytaskListHashMap.put("day15TaskList", listview15);
+ mytaskListHashMap.put("day16TaskList", listview16);
+ mytaskListHashMap.put("day17TaskList", listview17);
+ mytaskListHashMap.put("day18TaskList", listview18);
+ mytaskListHashMap.put("day19TaskList", listview19);
+ mytaskListHashMap.put("day20TaskList", listview20);
+ mytaskListHashMap.put("day21TaskList", listview21);
+ mytaskListHashMap.put("day22TaskList", listview22);
+ mytaskListHashMap.put("day23TaskList", listview23);
+ mytaskListHashMap.put("day24TaskList", listview24);
+ mytaskListHashMap.put("day25TaskList", listview25);
+ mytaskListHashMap.put("day26TaskList", listview26);
+ mytaskListHashMap.put("day27TaskList", listview27);
+ mytaskListHashMap.put("day28TaskList", listview28);
+ }
+
+ private void setTasks(ObservableList taskList) {
+ logger.info(" set tasks ");
+ initTaskListHashMap(taskListHashMap);
+ for (int i = 0; i < taskList.size(); i++) {
+ if (!taskList.get(i).getEndTiming().isFloating()) {
+ if (taskList.get(i).isRecurring()) {
+ for (int k = 0; k < taskList.get(i).getOccurrences().size(); k++) {
+ for (int j = 0; j < 28; j++) {
+ ListView currentTaskList = taskListHashMap.get("day" + (j + 1) + "TaskList");
+ String labelDate = dayHashMap.get("day" + (j + 1)).getText().toString();
+ String taskDate = taskList.get(i).getOccurrences().get(k).getEndTiming().toString();
+ String[] taskListDateData = taskDate.toString().split("/");
+
+ String test = String.valueOf(
+ taskList.get(i).getOccurrences().get(k).getEndTiming().getTiming().getMonth() + 1
+ );
+ String taskDateMonth = String.valueOf(
+ taskList.get(i).getOccurrences().get(k).getEndTiming().getTiming().getMonth() + 1
+ );
+ String taskDateDate = String.valueOf(
+ taskList.get(i).getOccurrences().get(k).getEndTiming().getTiming().getDate()
+ );
+
+
+ if ((taskDateMonth + "/" + taskDateDate).equals(labelDate)) {
+ currentTaskList.getItems().addAll(taskList.get(i).getDescription().toString());
+
+ }
+ }
+ }
+ } else {
+ for (int j = 0; j < 28; j++) {
+ ListView currentTaskList = taskListHashMap.get("day" + (j + 1) + "TaskList");
+ String labelDate = dayHashMap.get("day" + (j + 1)).getText().toString();
+ Date taskDate = taskList.get(i).getEndTiming().getTiming();
+ String[] taskListDateData = taskDate.toString().split("/");
+ String taskDateMonth = String.valueOf(taskDate.getMonth() + 1);
+ String taskDateDate = String.valueOf(taskDate.getDate());
+ if ((taskDateMonth + "/" + taskDateDate).equals(labelDate)) {
+ currentTaskList.getItems().addAll(taskList.get(i).getDescription().toString());
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ private void initDayHashMap(HashMap dayHash) {
+ dayHash.put("day1", day1);
+ dayHash.put("day2", day2);
+ dayHash.put("day3", day3);
+ dayHash.put("day4", day4);
+ dayHash.put("day5", day5);
+ dayHash.put("day6", day6);
+ dayHash.put("day7", day7);
+ dayHash.put("day8", day8);
+ dayHash.put("day9", day9);
+ dayHash.put("day10", day10);
+ dayHash.put("day11", day11);
+ dayHash.put("day12", day12);
+ dayHash.put("day13", day13);
+ dayHash.put("day14", day14);
+ dayHash.put("day15", day15);
+ dayHash.put("day16", day16);
+ dayHash.put("day17", day17);
+ dayHash.put("day18", day18);
+ dayHash.put("day19", day19);
+ dayHash.put("day20", day20);
+ dayHash.put("day21", day21);
+ dayHash.put("day22", day22);
+ dayHash.put("day23", day23);
+ dayHash.put("day24", day24);
+ dayHash.put("day25", day25);
+ dayHash.put("day26", day26);
+ dayHash.put("day27", day27);
+ dayHash.put("day28", day28);
+ }
+
+ private void setDate(int dDate, int dMonth, int dYear) {
+ logger.info(" set Date ");
+ SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+ Date date = new Date();
+ if (dDate != 0) {
+ try {
+ // date =
+ // fmt.parse(Integer.toString(Year)+"-"+Integer.toString(Month)+"-"+Integer.toString(Date));
+ date = fmt.parse(String.valueOf(dYear)
+ + "-" + String.valueOf(dMonth) + "-" + String.valueOf(dDate));
+ } catch (java.text.ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ initDayHashMap(dayHashMap);
+ String dayOfTheWeek = DAY.format(date);
+
+ Calendar firstDay = Calendar.getInstance();
+ if (dDate != 0) {
+ firstDay.set(Calendar.YEAR, dYear);
+
+ // We will have to increment the month field by 1
+
+ firstDay.set(Calendar.MONTH, dMonth - 1);
+
+ // As the month indexing starts with 0
+
+ firstDay.set(Calendar.DAY_OF_MONTH, dDate);
+ }
+ Date firstDate;
+ firstDate = firstDay.getTime();
+
+ if ("星期一".equals(dayOfTheWeek) || "Monday".equals(dayOfTheWeek)) {
+ firstDay.add(Calendar.DATE, -1);
+ } else if ("星期二".equals(dayOfTheWeek) || "Tuesday".equals(dayOfTheWeek)) {
+ firstDay.add(Calendar.DATE, -2);
+ } else if ("星期三".equals(dayOfTheWeek) || "Wednesday".equals(dayOfTheWeek)) {
+ firstDay.add(Calendar.DATE, -3);
+ } else if ("星期四".equals(dayOfTheWeek) || "Thursday".equals(dayOfTheWeek)) {
+ firstDay.add(Calendar.DATE, -4);
+ } else if ("星期五".equals(dayOfTheWeek) || "Friday".equals(dayOfTheWeek)) {
+ firstDay.add(Calendar.DATE, -5);
+ } else if ("星期六".equals(dayOfTheWeek) || "Saturday".equals(dayOfTheWeek)) {
+ firstDay.add(Calendar.DATE, -6);
+ }
+
+ firstDate = firstDay.getTime();
+ int firstDateYear = Integer.valueOf(YEAR.format(firstDate));
+ int firstDateMonth = Integer.valueOf(MONTH.format(firstDate));
+ int firstDateDate = Integer.valueOf(DATE.format(firstDate));
+
+ for (int count = 1; count <= 28; count++) {
+ dayHashMap.get("day" + count).setText(Integer.toString(firstDateMonth)
+ + "/" + Integer.toString(firstDateDate));
+ firstDateDate++;
+ if (firstDateMonth == 2 && firstDateDate > 29 && firstDateYear % 4 == 0) {
+ firstDateMonth += 1;
+ firstDateDate = 1;
+ } else if (firstDateMonth == 2 && firstDateDate > 28 && firstDateYear % 4 != 0) {
+ firstDateMonth += 1;
+ firstDateDate = 1;
+ } else if ((firstDateMonth == 1 || firstDateMonth == 3 || firstDateMonth == 5 ||
+ firstDateMonth == 7 || firstDateMonth == 8 || firstDateMonth == 10 ||
+ firstDateMonth == 12) && firstDateDate > 31) {
+ if (firstDateMonth == 12)firstDateMonth = 1;
+ else firstDateMonth += 1;
+ firstDateDate = 1;
+ } else if ((firstDateMonth == 2 || firstDateMonth == 4 || firstDateMonth == 6 ||
+ firstDateMonth == 9 || firstDateMonth == 11) && firstDateDate > 30) {
+ firstDateMonth += 1;
+ firstDateDate = 1;
+ }
+
+ }
+ }
+}
+```
+###### /java/seedu/task/ui/CommandBox.java
+``` java
+ updateCalender(this.mainwindow , logic.getFilteredTaskList() , 0 , 0 , 0);
+```
+###### /resources/view/CalenderPanel.fxml
+``` fxml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/collated/main/A0164212U.md b/collated/main/A0164212U.md
new file mode 100644
index 000000000000..c5f230434d33
--- /dev/null
+++ b/collated/main/A0164212U.md
@@ -0,0 +1,1067 @@
+# A0164212U
+###### /java/seedu/task/commons/core/Messages.java
+``` java
+ public static final String MESSSAGE_INVALID_TIMING_ORDER = "The start and end times are not in chronological order";
+
+}
+```
+###### /java/seedu/task/commons/exceptions/IllegalTimingOrderException.java
+``` java
+package seedu.task.commons.exceptions;
+
+/**
+ * Signals that start timing is after end timing.
+ */
+public class IllegalTimingOrderException extends Exception {
+ /**
+ * @param message should contain relevant information on the failed constraint(s)
+ */
+ public IllegalTimingOrderException(String message) {
+ super(message);
+ }
+}
+```
+###### /java/seedu/task/logic/commands/AddCommand.java
+``` java
+ /**
+ * Creates an AddCommand using raw values.
+ *
+ * @throws IllegalValueException if any of the raw values are invalid
+ */
+ public AddCommand(String name, String priority, String startTiming, String endTiming,
+ String recurFreq, Set tags)
+ throws IllegalValueException, IllegalTimingOrderException {
+ final Set tagSet = new HashSet<>();
+ for (String tagName : tags) {
+ tagSet.add(new Tag(tagName));
+ }
+ boolean recurring = (recurFreq != null);
+
+ this.toAdd = new Task(
+ new Description(name),
+ new Priority(priority),
+ new Timing(startTiming),
+ new Timing(endTiming),
+ new UniqueTagList(tagSet),
+ recurring,
+ new RecurringFrequency(recurFreq)
+ );
+ if (!Timing.checkTimingOrder(toAdd.getStartTiming(), toAdd.getEndTiming())) {
+ logger.warning("Timing is not in the correct order");
+ throw new IllegalTimingOrderException(MESSSAGE_INVALID_TIMING_ORDER);
+ }
+ }
+
+ public AddCommand(ReadOnlyTask task) {
+ this.toAdd = (Task) task;
+ }
+```
+###### /java/seedu/task/logic/commands/CompleteCommand.java
+``` java
+ @Override
+ public CommandResult execute() throws CommandException {
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ if (lastShownList.size() <= targetIndex) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToComplete = lastShownList.get(targetIndex);
+ Task newTask = null;
+ Task completedTask;
+
+ try {
+ if (taskToComplete.isRecurring()) {
+ newTask = Task.extractOccurrence(taskToComplete);
+ model.addTask(newTask);
+ completedTask = createCompletedTask(newTask, completeTaskDescriptor);
+ int newIndex = model.getFilteredTaskList().indexOf(newTask);
+ completedTask.setComplete();
+ model.updateTask(newIndex, completedTask);
+ model.updateFilteredListToShowAll();
+ logger.info(MESSAGE_COMPLETE_TASK_SUCCESS);
+ return new CommandResult(String.format(MESSAGE_COMPLETE_TASK_SUCCESS, newTask));
+ } else {
+ completedTask = createCompletedTask(taskToComplete, completeTaskDescriptor);
+ completedTask.setComplete();
+ model.updateTask(targetIndex, completedTask);
+ model.updateFilteredListToShowAll();
+ logger.info(MESSAGE_COMPLETE_TASK_SUCCESS);
+ return new CommandResult(String.format(MESSAGE_COMPLETE_TASK_SUCCESS, taskToComplete));
+ }
+ } catch (UniqueTaskList.DuplicateTaskException dpe) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ }
+```
+###### /java/seedu/task/logic/commands/DeleteCommand.java
+``` java
+ @Override
+ public CommandResult execute() throws CommandException {
+
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+
+ if (lastShownList.size() < targetIndex) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToDelete = lastShownList.get(targetIndex - 1);
+ Task deleteOccurrence = null;
+
+ if (isSpecific && taskToDelete.getOccurrences().size() > 1) {
+ Task taskToAdd = new Task(taskToDelete);
+ try {
+ deleteOccurrence = Task.extractOccurrence(taskToDelete);
+ model.deleteThisTask(taskToDelete, taskToAdd);
+ logger.info("Deleting specific instance of recurring task");
+ return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, deleteOccurrence));
+ } catch (DuplicateTaskException e) {
+ throw new CommandException(AddCommand.MESSAGE_DUPLICATE_TASK);
+ } catch (TaskNotFoundException tnfe) {
+ assert false : MESSAGE_MISSING_TASK;
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ } else {
+ try {
+ model.deleteTask(taskToDelete);
+ } catch (TaskNotFoundException tnfe) {
+ assert false : MESSAGE_MISSING_TASK;
+ }
+ }
+ return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete));
+ }
+
+}
+```
+###### /java/seedu/task/logic/commands/EditCommand.java
+``` java
+ @Override
+ public CommandResult execute() throws CommandException {
+ List lastShownList = model.getFilteredTaskList();
+
+ if (filteredTaskListIndex >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToEdit = lastShownList.get(filteredTaskListIndex);
+ Task newTask = null;
+ Task editedTask;
+
+ try {
+ if (isSpecific) {
+ newTask = Task.extractOccurrence(taskToEdit);
+ ReadOnlyTask copyRecurTask = new Task(taskToEdit);
+ editedTask = createEditedTask(newTask, editTaskDescriptor);
+ model.updateThisTask(filteredTaskListIndex, copyRecurTask, editedTask);
+ logger.info("Editing a specific occurrence of a recurring task");
+ } else {
+ editedTask = createEditedTask(taskToEdit, editTaskDescriptor);
+ model.updateTask(filteredTaskListIndex, editedTask);
+ }
+ } catch (IllegalTimingOrderException e) {
+ throw new CommandException(MESSSAGE_INVALID_TIMING_ORDER);
+ } catch (UniqueTaskList.DuplicateTaskException dpe) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+
+ model.updateFilteredListToShowAll();
+ logger.info(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
+ return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
+ }
+```
+###### /java/seedu/task/model/ModelManager.java
+``` java
+ /**
+ * @param ReadOnlyTask
+ * internally sets task.occurrenceIndexList for occurrences that match given keywords for task
+ * @return true if keywords are present in the given task
+ */
+ @Override
+ public boolean run(ReadOnlyTask task) {
+ boolean isValid = false;
+ ArrayList occurrenceIndexList = new ArrayList();
+ for (int i = 0; i < task.getOccurrences().size(); i++) {
+ final int finalIndex = i;
+ if (filterMultiple(task.getDescription().description, task.getPriority().value,
+ task.getOccurrences().get(finalIndex).getStartTiming().value,
+ task.getOccurrences().get(finalIndex).getEndTiming().value)) {
+ occurrenceIndexList.add(i);
+ isValid = true;
+ }
+ }
+ task.setOccurrenceIndexList(occurrenceIndexList);
+ return isValid;
+ }
+
+ /**
+ * @param string variable number of strings
+ * @return true is any one of the strings is present in executed command
+ */
+ public boolean filterMultiple(String...strings) {
+ boolean isValid = false;
+ for (String s : strings) {
+ isValid = isValid || filter(s);
+ }
+ return isValid;
+ }
+
+ /**
+ * @param string
+ * @return true if string exists in keywords provided by command
+ */
+ public boolean filter(String s) {
+ return (nameKeyWords.stream()
+ .filter(keyword -> StringUtil.containsWordIgnoreCase(s, keyword))
+ .findAny()
+ .isPresent());
+ }
+```
+###### /java/seedu/task/model/task/Priority.java
+``` java
+package seedu.task.model.task;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+
+/**
+ * Represents a Task's priority number in the Task Manager.
+ * A smaller priority number indicates a higher priority.
+ * Guarantees: immutable; is valid as declared in {@link #isValidPriority(String)}
+ */
+public class Priority implements Comparable {
+
+ public static final String MESSAGE_PRIORITY_CONSTRAINTS = "Task priority should be between 1-3";
+ public static final String PRIORITY_HIGH = "1";
+ public static final String PRIORITY_MEDIUM = "2";
+ public static final String PRIORITY_LOW = "3";
+ public static final String PRIORITY_HIGH_COLOR = "red";
+ public static final String PRIORITY_MEDIUM_COLOR = "darkorange";
+ public static final String PRIORITY_LOW_COLOR = "yellow";
+
+ public final String value;
+
+ private String priorityColor;
+
+ /**
+ * Validates given priority number.
+ *
+ * @throws IllegalValueException if given priority string is invalid.
+ */
+ public Priority(String priority) throws IllegalValueException {
+ if (priority != null) {
+ String trimmedPriority = priority.trim();
+ if (!isValidPriority(trimmedPriority)) {
+ throw new IllegalValueException(MESSAGE_PRIORITY_CONSTRAINTS);
+ }
+ this.value = trimmedPriority;
+ } else {
+ this.value = PRIORITY_LOW;
+ }
+
+ setPriorityColor(this.value);
+ }
+
+ /**
+ * Returns true if a given string is a valid task priority.
+ */
+ public static boolean isValidPriority(String test) {
+ return (test.equals(PRIORITY_HIGH) || test.equals(PRIORITY_MEDIUM) || test.equals(PRIORITY_LOW));
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Priority // instanceof handles nulls
+ && this.value.equals(((Priority) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ public String getPriorityColor() {
+ return priorityColor;
+ }
+
+ public void setPriorityColor(String priorityValue) {
+ switch(priorityValue) {
+ case PRIORITY_HIGH:
+ priorityColor = PRIORITY_HIGH_COLOR;
+ break;
+ case PRIORITY_MEDIUM:
+ priorityColor = PRIORITY_MEDIUM_COLOR;
+ break;
+ case PRIORITY_LOW:
+ priorityColor = PRIORITY_LOW_COLOR;
+ break;
+ default:
+ priorityColor = PRIORITY_LOW_COLOR;
+ break;
+ }
+ }
+
+```
+###### /java/seedu/task/model/task/RecurringFrequency.java
+``` java
+package seedu.task.model.task;
+
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.IllegalValueException;
+
+/**
+ * Represents a Task's frequency in the ToDo list.
+ * Guarantees: immutable; is valid as declared in {@link #isValidFrequency(String)}
+ */
+public class RecurringFrequency {
+ private static final Logger logger = LogsCenter.getLogger(RecurringFrequency.class);
+
+ public static final String MESSAGE_FREQUENCY_CONSTRAINTS =
+ "Frequency must be a number followerd by d (day), m (month), y (year) no spaces";
+
+ public static final String FREQUENCY_VALIDATION_REGEX = "^[0-9]+[ydmHDY]";
+ public static final String NULL_FREQUENCY = "0";
+
+ public final String frequency;
+
+ public static final int DAY_LIMIT = 60; //two months
+ public static final int MONTH_LIMIT = 12; //one year
+ public static final int YEAR_LIMIT = 4; //four years
+
+ /**
+ * Validates given frequency.
+ *
+ * @throws IllegalValueException if given frequency string is invalid.
+ */
+ public RecurringFrequency(String frequency) throws IllegalValueException {
+ if (frequency != null) {
+ String trimmedFrequency = frequency.trim();
+ if (!isValidFrequency(trimmedFrequency)) {
+ logger.severe("Invalid value for frequency...");
+ throw new IllegalValueException(MESSAGE_FREQUENCY_CONSTRAINTS);
+ }
+ this.frequency = trimmedFrequency;
+ } else {
+ logger.info("Setting frequency to default value...");
+ this.frequency = NULL_FREQUENCY;
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid frequency.
+ */
+ public static boolean isValidFrequency(String test) {
+ return test.matches(FREQUENCY_VALIDATION_REGEX) || test.equals(NULL_FREQUENCY);
+ }
+
+ @Override
+ public String toString() {
+ return frequency;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof RecurringFrequency // instanceof handles nulls
+ && this.frequency.equals(((RecurringFrequency) other).frequency)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return frequency.hashCode();
+ }
+
+ public int getFrequencyNumber() {
+ String numberOnlyString = frequency.replaceAll("[^0-9]", "");
+ int numberOnly = Integer.parseInt(numberOnlyString);
+ return numberOnly;
+ }
+
+ public String getFrequencyCharacter() {
+ String characterOnly = frequency.replaceAll("[^A-Za-z]", "");
+ return characterOnly;
+ }
+}
+```
+###### /java/seedu/task/model/task/RecurringTaskOccurrence.java
+``` java
+package seedu.task.model.task;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.CollectionUtil;
+
+public class RecurringTaskOccurrence {
+ private Timing startTiming;
+ private Timing endTiming;
+ private boolean complete;
+
+ public RecurringTaskOccurrence(Timing startTime, Timing endTime) {
+ assert !CollectionUtil.isAnyNull(startTime, endTime);
+ this.startTiming = startTime;
+ this.endTiming = endTime;
+ this.complete = false;
+ }
+
+ public RecurringTaskOccurrence() throws IllegalValueException {
+ this(new Timing(Timing.getTodayDate()), new Timing(Timing.getTodayDate()));
+ }
+
+ public Timing getStartTiming() {
+ return startTiming;
+ }
+
+ public void setStartTiming(Timing startTime) {
+ assert startTime != null;
+ this.startTiming = startTime;
+ }
+
+ public Timing getEndTiming() {
+ return endTiming;
+ }
+
+ public void setEndTiming(Timing endTime) {
+ assert endTime != null;
+ this.endTiming = endTime;
+
+ }
+
+ public void setComplete(boolean complete) {
+ this.complete = complete;
+ }
+
+ public boolean isComplete() {
+ return complete;
+ }
+
+ public boolean equals(RecurringTaskOccurrence other) {
+ return this.startTiming.equals(other.startTiming) && this.endTiming.equals(other.endTiming);
+ }
+}
+```
+###### /java/seedu/task/model/task/Task.java
+``` java
+package seedu.task.model.task;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.CollectionUtil;
+import seedu.task.model.tag.UniqueTagList;
+
+/**
+ * Represents a Task in the Task Manager. Guarantees: details are present and not
+ * null, field values are validated.
+ */
+public class Task implements ReadOnlyTask, Comparable {
+ private static final Logger logger = LogsCenter.getLogger(Task.class);
+
+ private Description description;
+ private Priority priority;
+ private ArrayList occurrences;
+ private boolean recurring;
+ private UniqueTagList tags;
+ private RecurringFrequency frequency;
+ private ArrayList occurrenceIndexList = new ArrayList();
+
+ public static final String MESSAGE_MISSING_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+ public static final String MESSAGE_ILLEGAL_TIMING_VALUES = "Illegal Value for timings";
+ public static final String MESSAGE_ILLEGAL_FREQUENCY_VALUES = "Illegal Value for frequency";
+
+ /**
+ * Every field must be present and not null.
+ * @throws IllegalValueException
+ */
+ public Task(Description description, Priority priority, Timing startTiming, Timing endTiming,
+ UniqueTagList tags, boolean recurring, RecurringFrequency frequency) throws IllegalValueException {
+ assert !CollectionUtil.isAnyNull(description, priority, startTiming, tags);
+ this.description = description;
+ this.priority = priority;
+ this.occurrences = new ArrayList();
+ this.tags = new UniqueTagList(tags); // protect internal tags from
+ // changes in the arg list
+ this.recurring = recurring;
+ this.frequency = frequency;
+ setOccurrences(startTiming, endTiming);
+ occurrenceIndexList.add(0);
+ }
+
+ public Task(Description description, Priority priority, ArrayList occurrences,
+ UniqueTagList tags, boolean recurring, RecurringFrequency frequency) {
+ assert !CollectionUtil.isAnyNull(description, priority, occurrences, tags, recurring, frequency);
+ this.description = description;
+ this.priority = priority;
+ this.occurrences = new ArrayList(occurrences);
+ this.tags = new UniqueTagList(tags);
+ this.recurring = recurring;
+ this.frequency = frequency;
+ }
+
+
+ /**
+ * Creates a copy of the given ReadOnlyTask.
+ */
+ public Task(ReadOnlyTask source) {
+ this(source.getDescription(), source.getPriority(), source.getOccurrences(),
+ source.getTags(), source.isRecurring(), source.getFrequency());
+ }
+
+ @Override
+ public ArrayList getOccurrenceIndexList() {
+ return occurrenceIndexList;
+ };
+
+ @Override
+ public void setOccurrenceIndexList(ArrayList list) {
+ occurrenceIndexList = list;
+ };
+
+ public void setDescription(Description description) {
+ assert description != null;
+ this.description = description;
+ }
+
+ @Override
+ public Description getDescription() {
+ return description;
+ }
+
+ public void setPriority(Priority priority) {
+ assert priority != null;
+ this.priority = priority;
+ }
+
+ @Override
+ public Priority getPriority() {
+ return priority;
+ }
+
+ @Override
+ public void setStartTiming(Timing startTiming) {
+ assert startTiming != null;
+ this.occurrences.get(0).setStartTiming(startTiming);
+ }
+
+ @Override
+ public Timing getStartTiming(int i) { //add parameter to index into correct endTime
+ if (this.occurrences.size() == 0) {
+ try {
+ return new Timing(Timing.TIMING_NOT_SPECIFIED);
+ } catch (IllegalValueException e) {
+ assert false : "Illegal timing value";
+ }
+ }
+ return this.occurrences.get(i).getStartTiming();
+ }
+
+ @Override
+ public Timing getStartTiming() {
+ return getStartTiming(0);
+ }
+
+ @Override
+ public void setEndTiming(Timing endTiming) { //add parameter to index into correct endTime
+ assert endTiming != null;
+ this.occurrences.get(0).setEndTiming(endTiming);
+ }
+
+ @Override
+ public Timing getEndTiming() {
+ if (this.occurrences.size() == 0) {
+ try {
+ return new Timing(Timing.TIMING_NOT_SPECIFIED);
+ } catch (IllegalValueException e) {
+ assert false : "Illegal timing value";
+ }
+ }
+ return this.occurrences.get(0).getEndTiming();
+ }
+
+ public void setComplete() { //add parameter to index into correct endTime
+ this.occurrences.get(0).setComplete(true);
+ }
+
+ @Override
+ public boolean isComplete() { //add parameter to index into correct endTime
+ return this.occurrences.get(0).isComplete();
+ }
+
+ @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);
+ }
+
+ /**
+ * Updates this task with the details of {@code replacement}.
+ */
+ public void resetData(ReadOnlyTask replacement) {
+ assert replacement != null;
+
+ this.setDescription(replacement.getDescription());
+ this.setPriority(replacement.getPriority());
+ this.setOccurrences(replacement.getOccurrences());
+ this.setTags(replacement.getTags());
+ this.setFrequency(replacement.getFrequency());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ReadOnlyTask // instanceof handles nulls
+ && this.isSameStateAs((ReadOnlyTask) other));
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing
+ // your own
+ return Objects.hash(description, priority,
+ occurrences.get(0).getStartTiming(), occurrences.get(0).getEndTiming(),
+ tags, recurring, frequency);
+ }
+
+ @Override
+ public RecurringFrequency getFrequency() {
+ return frequency;
+ }
+
+ @Override
+ public void setFrequency(RecurringFrequency frequency) {
+ this.frequency = frequency;
+ }
+
+ @Override
+ public String toString() {
+ return getAsText();
+ }
+
+ @Override
+ public boolean isRecurring() {
+ return recurring;
+ }
+
+ @Override
+ public void setRecurring(boolean recurring) {
+ this.recurring = recurring;
+ }
+
+ @Override
+ public ArrayList getOccurrences() {
+ return occurrences;
+ }
+
+ /**
+ * @param string
+ * @return SimpleDateFormat object of passed in string
+ */
+ private SimpleDateFormat retriveDateFormat(String s) {
+ assert s != null;
+ SimpleDateFormat format;
+ String basicFormat = "dd/MM/yyyy";
+ String extendedFormat = "HH:mm dd/MM/yyyy";
+ if (s.length() <= basicFormat.length()) {
+ format = new SimpleDateFormat(basicFormat);
+ } else {
+ format = new SimpleDateFormat(extendedFormat);
+ }
+ return format;
+ }
+
+ @Override
+ public void removeOccurrence(int i) {
+ this.occurrences.remove(i);
+ }
+
+ @Override
+ public void setOccurrences(ArrayList occurrences) {
+ this.occurrences = occurrences;
+ }
+
+ /** If frequency is in years - support up to 4 years
+ * If frequency is in days - support up to 60 days
+ * If frequency is in months - support up to 12 months
+ * @param startTime
+ * @param endTime
+ * @throws IllegalValueException
+ */
+ public void setOccurrences(Timing initialStartTime, Timing initialEndTime) throws IllegalValueException {
+ logger.info("Setting initial occurrence...");
+ this.occurrences.add(new RecurringTaskOccurrence(initialStartTime, initialEndTime));
+ if (isRecurring()) {
+ if (initialStartTime.timing == null || initialEndTime.timing == null) {
+ logger.severe("Start or End timing not specified for recurring task");
+ throw new IllegalValueException(MESSAGE_MISSING_TIMING);
+ }
+ String freqCharacter = frequency.getFrequencyCharacter();
+ switch (freqCharacter) {
+ case "d":
+ int dayLimit = RecurringFrequency.DAY_LIMIT;
+ int day = Calendar.DATE;
+ setOccurrences(initialStartTime, initialEndTime, dayLimit, day);
+ break;
+ case "m":
+ int monthLimit = RecurringFrequency.MONTH_LIMIT;
+ int month = Calendar.MONTH;
+ setOccurrences(initialStartTime, initialEndTime, monthLimit, month);
+ break;
+ case "y":
+ int yearLimit = RecurringFrequency.YEAR_LIMIT;
+ int year = Calendar.YEAR;
+ setOccurrences(initialStartTime, initialEndTime, yearLimit, year);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param initialStartTime
+ * @param initialEndTime
+ * @param limit specifies the number of iterations to add to the occurrences list
+ * @param offSet specifies the calendar field to be updated
+ */
+ public void setOccurrences(Timing initialStartTime, Timing initialEndTime, int limit, int offSet) {
+ int freqNumber = frequency.getFrequencyNumber();
+ Calendar cal1 = Calendar.getInstance();
+ Calendar cal2 = Calendar.getInstance();
+ cal1.setTime(initialStartTime.getTiming());
+ cal2.setTime(initialEndTime.getTiming());
+ SimpleDateFormat startTimeFormat = retriveDateFormat(initialStartTime.toString());
+ SimpleDateFormat endTimeFormat = retriveDateFormat(initialEndTime.toString());
+ String tempStartTime;
+ String tempEndTime;
+ Timing tempStart = null;
+ Timing tempEnd = null;
+ RecurringTaskOccurrence occurrenceToAdd;
+
+ for (int i = 1; i < limit; i += freqNumber) {
+ cal1.add(offSet, freqNumber);
+ cal2.add(offSet, freqNumber);
+ tempStartTime = startTimeFormat.format(cal1.getTime());
+ tempEndTime = endTimeFormat.format(cal2.getTime());
+ try {
+ tempStart = new Timing(tempStartTime);
+ tempEnd = new Timing(tempEndTime);
+ } catch (IllegalValueException e) {
+ assert false : MESSAGE_ILLEGAL_TIMING_VALUES;
+ }
+ occurrenceToAdd = new RecurringTaskOccurrence(tempStart, tempEnd);
+ occurrences.add(occurrenceToAdd);
+ }
+ }
+
+ /**
+ * @param taskToModify ReadOnlyTask object
+ * @return new Task instance with only one occurrence;
+ * modifies the parameter by removing the respective occurrence for additional functionality
+ * @throws IllegalValueException
+ */
+ public static Task extractOccurrence(ReadOnlyTask taskToModify) throws IllegalValueException {
+ Task newTask = null;
+ if (taskToModify.getOccurrenceIndexList().size() == 0) {
+ taskToModify.getOccurrenceIndexList().add(0);
+ }
+ int occurrenceIndex = taskToModify.getOccurrenceIndexList().get(0);
+ RecurringFrequency freq = null;
+ try {
+ freq = new RecurringFrequency(RecurringFrequency.NULL_FREQUENCY);
+ } catch (IllegalValueException e1) {
+ assert false : MESSAGE_ILLEGAL_FREQUENCY_VALUES;
+ }
+ newTask = new Task(
+ taskToModify.getDescription(),
+ taskToModify.getPriority(),
+ taskToModify.getOccurrences().get(occurrenceIndex).getStartTiming(),
+ taskToModify.getOccurrences().get(occurrenceIndex).getEndTiming(),
+ taskToModify.getTags(),
+ false,
+ freq);
+ newTask.getStartTiming().setTiming(newTask.getStartTiming().toString());
+ newTask.getEndTiming().setTiming(newTask.getEndTiming().toString());
+ taskToModify.removeOccurrence(occurrenceIndex);
+
+ return newTask;
+ }
+
+ /**
+ * converts readOnlyTask object to Task object
+ * @param readOnlyTask
+ * @return Task
+ */
+ public static Task readOnlyToTask(ReadOnlyTask readOnlyTask) {
+ assert readOnlyTask != null;
+ Task task = new Task(
+ readOnlyTask.getDescription(),
+ readOnlyTask.getPriority(),
+ readOnlyTask.getOccurrences(),
+ readOnlyTask.getTags(),
+ readOnlyTask.isRecurring(),
+ readOnlyTask.getFrequency());
+ return task;
+ }
+
+```
+###### /java/seedu/task/model/task/Timing.java
+``` java
+package seedu.task.model.task;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+
+/**
+ * Represents a Task's timing in the Task Manager. Guarantees: immutable; is valid
+ * as declared in {@link #isValidTiming(String)}
+ */
+public class Timing implements Comparable {
+
+ public static final String MESSAGE_TIMING_CONSTRAINTS =
+ "Task timing should be in the format HH:mm dd/MM/yyyy OR dd/MM/yyyy " +
+ "Can use only HH:mm if today is the default date";
+ public static final String[] TIMING_FORMAT = {"HH:mm dd/MM/yyyy", "dd/MM/yyyy"};
+ public static final String DEFAULT_DATE_INPUT_FORMAT = "HH:mm";
+ public static final String TIMING_NOT_SPECIFIED = "floating";
+
+ public final String value;
+ public Date timing;
+
+ /**
+ * Validates given timing.
+ * Sets today's date as default if only time is specified
+ *
+ * @throws IllegalValueException
+ * if given timing string is invalid.
+ */
+ public Timing(String time) throws IllegalValueException {
+ int defaultDateLen = DEFAULT_DATE_INPUT_FORMAT.length();
+ if (time != null) {
+ String trimmedTiming = time.trim();
+ if (trimmedTiming.length() <= defaultDateLen) {
+ trimmedTiming = trimmedTiming + " " + Timing.getTodayDate();
+ }
+ if (!trimmedTiming.equals(TIMING_NOT_SPECIFIED) && !isValidTiming(trimmedTiming)) {
+ throw new IllegalValueException(MESSAGE_TIMING_CONSTRAINTS);
+ }
+ this.value = trimmedTiming;
+ setTiming(trimmedTiming);
+ } else {
+ this.value = TIMING_NOT_SPECIFIED;
+ this.timing = null;
+ }
+ }
+
+ public Timing() throws IllegalValueException {
+ this(null);
+ }
+
+ /**
+ * Returns if a given string is a valid timing.
+ */
+ public static boolean isValidTiming(String test) {
+ boolean isValid = false;
+ int dateFormat1Len = TIMING_FORMAT[0].length();
+ int dateFormat2Len = TIMING_FORMAT[1].length();
+ if (test.equals(TIMING_NOT_SPECIFIED)) {
+ isValid = true;
+ } else if (test.length() == dateFormat1Len || test.length() == dateFormat2Len) {
+ for (int i = 0; i < TIMING_FORMAT.length; i++) {
+ SimpleDateFormat sdf = new SimpleDateFormat(TIMING_FORMAT[i]);
+ sdf.setLenient(false);
+ try {
+ // throws ParseException if timing is not valid
+ Date date = sdf.parse(test);
+ // check if year is truly 4 digits (the 'yyyy' regex does not support this)
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ if (cal.get(Calendar.YEAR) >= 1000 && cal.get(Calendar.YEAR) <= 9999) {
+ isValid = true;
+ }
+ break;
+ } catch (ParseException e) {
+ }
+ }
+ }
+ return isValid;
+ }
+
+ public void setTiming(String time) {
+ for (int i = 0; i < TIMING_FORMAT.length; i++) {
+ SimpleDateFormat sdf = new SimpleDateFormat(TIMING_FORMAT[i]);
+ sdf.setLenient(false);
+ try {
+ // throws ParseException if timing is not valid
+ Date date = sdf.parse(time);
+ this.timing = date;
+ break;
+ } catch (ParseException e) {
+ }
+ }
+ }
+
+ public Date getTiming() {
+ return timing;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this.value == null) {
+ return false;
+ }
+ return other == this // short circuit if same object
+ || (other instanceof Timing // instanceof handles nulls
+ && this.value.equals(((Timing) other).value)); // state
+ // check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ /**
+ * @return returns today's date as a string in "dd/MM/yyyy" format
+ */
+ public static String getTodayDate() {
+ DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
+ Date date = new Date();
+ String dateString = dateFormat.format(date);
+ return dateString;
+ }
+
+ /**
+ *
+ * @param time1
+ * @param time2
+ * @return returns True if time1 is before time2
+ */
+ public static boolean checkTimingOrder(Timing time1, Timing time2) {
+ boolean isOrdered = true;
+ if (time1 == null || time1.value.equals(TIMING_NOT_SPECIFIED)
+ || time2 == null || time2.value.equals(TIMING_NOT_SPECIFIED)) {
+ return isOrdered;
+ }
+ Calendar cal1 = Calendar.getInstance();
+ Calendar cal2 = Calendar.getInstance();
+ cal1.setTime(time1.getTiming());
+ cal2.setTime(time2.getTiming());
+
+ if (cal1.compareTo(cal2) > 0) {
+ isOrdered = false;
+ }
+
+ return isOrdered;
+ }
+
+ public boolean isFloating() {
+ return this.value.equals(TIMING_NOT_SPECIFIED);
+ }
+
+```
+###### /java/seedu/task/ui/PersonCard.java
+``` java
+ @FXML
+ private Label description;
+ @FXML
+ private Label id;
+ @FXML
+ private Label priority;
+ @FXML
+ private Label startTiming;
+ @FXML
+ private Label endTiming;
+ @FXML
+ private Label recurring;
+ @FXML
+ private FlowPane tags;
+
+ public PersonCard(ReadOnlyTask task, int displayedIndex) {
+ super(FXML);
+
+ description.setText(task.getDescription().description);
+ id.setText(displayedIndex + ". ");
+ priority.setText("Priority: " + task.getPriority().value);
+ priority.setStyle("-fx-background-color: " + task.getPriority().getPriorityColor() + ";");
+
+ if (task.getStartTiming().value.equals(Timing.TIMING_NOT_SPECIFIED)) {
+ startTiming.setText("");
+ } else if (task.getOccurrenceIndexList().size() == 0) {
+ startTiming.setText("Start Timing: " + task.getOccurrences().get(0).getStartTiming().value);
+ } else {
+ int index = task.getOccurrenceIndexList().get(0);
+ if (task.getOccurrences().size() <= index) {
+ index--;
+ }
+ startTiming.setText("Start Timing: " + task.getOccurrences().get(index).getStartTiming().value);
+ }
+
+ if (task.getEndTiming().value.equals(Timing.TIMING_NOT_SPECIFIED)) {
+ endTiming.setText("");
+ } else if (task.getOccurrenceIndexList().size() == 0) {
+ endTiming.setText("End Timing: " + task.getOccurrences().get(0).getEndTiming().value);
+ } else {
+ int index = task.getOccurrenceIndexList().get(0);
+ if (task.getOccurrences().size() <= index) {
+ index--;
+ }
+ endTiming.setText("End Timing: " + task.getOccurrences().get(index).getEndTiming().value);
+ }
+
+ if (task.isRecurring()) {
+ recurring.setText("Recurring Task: " + task.getFrequency().toString());
+ recurring.setStyle("-fx-background-color: pink;");
+ } else {
+ recurring.setText("");
+ }
+ initTags(task);
+ }
+```
+###### /resources/view/PersonListCard.fxml
+``` fxml
+
+
+
+
+
+```
+###### /resources/view/PersonListCard.fxml
+``` fxml
+
+
+
+
+
+
+```
diff --git a/collated/test/A0113795Y.md b/collated/test/A0113795Y.md
new file mode 100644
index 000000000000..f47e85e8ad4d
--- /dev/null
+++ b/collated/test/A0113795Y.md
@@ -0,0 +1,395 @@
+# A0113795Y
+###### /java/guitests/AddCommandTest.java
+``` java
+ //test monthly recurring task
+ TestTask[] currentList = td.getEmptyTasks();
+ TestTask taskToAdd = td.recMonth;
+ assertAddSuccess(taskToAdd, currentList);
+ currentList = TestUtil.addTasksToList(currentList, taskToAdd);
+ assertTrue(taskListPanel.isListMatching(currentList));
+ ArrayList hardCodedMonth = new ArrayList();
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/01/2017"), new Timing("05/01/2017")));
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/03/2017"), new Timing("05/03/2017")));
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/05/2017"), new Timing("05/05/2017")));
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/07/2017"), new Timing("05/07/2017")));
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/09/2017"), new Timing("05/09/2017")));
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/11/2017"), new Timing("05/11/2017")));
+ hardCodedMonth.add(new RecurringTaskOccurrence(new Timing("01/01/2018"), new Timing("05/01/2018")));
+ Task taskMonth = new Task(taskToAdd.getDescription(), taskToAdd.getPriority(),
+ taskToAdd.getStartTiming(), taskToAdd.getEndTiming(), taskToAdd.getTags(),
+ taskToAdd.isRecurring(), taskToAdd.getFrequency());
+ assertOccurrenceSame(hardCodedMonth, taskMonth.getOccurrences());
+```
+###### /java/guitests/AddCommandTest.java
+``` java
+ private void assertOccurrenceSame(ArrayList hardCoded
+ , ArrayList taskOccurrences) {
+ assertTrue(hardCoded.size() == taskOccurrences.size());
+ for (int i = 0; i < hardCoded.size(); i++) {
+ assertTrue(hardCoded.get(i).equals(taskOccurrences.get(i)));
+ }
+ }
+```
+###### /java/guitests/CompleteCommandTest.java
+``` java
+package guitests;
+
+import static org.junit.Assert.assertTrue;
+import static seedu.task.logic.commands.CompleteCommand.MESSAGE_COMPLETE_TASK_SUCCESS;
+
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import guitests.guihandles.TaskCardHandle;
+import seedu.task.TestApp;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.testutil.TaskBuilder;
+import seedu.task.testutil.TestTask;
+
+public class CompleteCommandTest extends AddressBookGuiTest {
+ TestTask[] currentList = td.getTypicalTasks();
+
+ @Before
+ public void reset_config() throws IOException {
+ TestApp testApp = new TestApp();
+ Config config = testApp.initConfig(Config.DEFAULT_CONFIG_FILE);
+ ConfigUtil.saveConfig(config, Config.DEFAULT_CONFIG_FILE);
+ commandBox.runCommand("clear");
+ }
+
+ @Test
+ public void completeSuccess() throws IllegalValueException {
+ commandBox.runCommand("clear");
+ for (int i = 0; i < currentList.length; i++) {
+ commandBox.runCommand(currentList[i].getAddCommand());
+ }
+
+ String completeTag = "complete";
+ TestTask taskToComplete = currentList[0];
+ TestTask taskCompleted = new TaskBuilder(taskToComplete).withTags(completeTag).build();
+
+
+ int taskListIndex = 1;
+ assertCompleteSuccess(taskListIndex, taskListIndex, taskCompleted);
+ }
+
+ private void assertCompleteSuccess(int taskListIndex, int currentListIndex,
+ TestTask completedTask) {
+
+ commandBox.runCommand("complete " + taskListIndex);
+
+ TaskCardHandle completedCard =
+ taskListPanel.navigateToTask(completedTask.getDescription().toString());
+ assertMatching(completedTask, completedCard);
+ currentList[currentListIndex - 1] = completedTask;
+ assertTrue(taskListPanel.isListMatching(currentList));
+ assertResultMessage(String.format(MESSAGE_COMPLETE_TASK_SUCCESS, completedTask));
+ }
+}
+```
+###### /java/guitests/DeleteCommandTest.java
+``` java
+ public void deletethis() {
+ commandBox.runCommand("clear");
+ TestTask taskToDelete = td.recMonth;
+ commandBox.runCommand(taskToDelete.getAddCommand());
+ commandBox.runCommand("01/03/2017");
+ commandBox.runCommand("deletethis 1");
+
+ // Check the first occurrence
+ commandBox.runCommand("find 01/01/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the deleted occurrence
+ commandBox.runCommand("find 01/03/2017");
+ assertResultMessage("0 tasks listed!");
+
+ // Check the second occurrence
+ commandBox.runCommand("find 01/05/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the third occurrence
+ commandBox.runCommand("find 01/07/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the fourth occurrence
+ commandBox.runCommand("find 01/09/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the fifth occurrence
+ commandBox.runCommand("find 01/11/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the sixth occurrence
+ commandBox.runCommand("find 01/01/2018");
+ assertResultMessage("1 tasks listed!");
+ }
+```
+###### /java/guitests/EditCommandTest.java
+``` java
+package guitests;
+import static org.junit.Assert.assertTrue;
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.ArrayList;
+
+import org.junit.Test;
+
+import guitests.guihandles.TaskCardHandle;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.EditCommand;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.tag.UniqueTagList.DuplicateTagException;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.RecurringTaskOccurrence;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.testutil.TaskBuilder;
+import seedu.task.testutil.TestTask;
+
+// TODO: reduce GUI tests by transferring some tests to be covered by lower level tests.
+public class EditCommandTest extends AddressBookGuiTest {
+
+ @Test
+ public void editAllFieldsSpecifiedSuccessForNormalTask() throws Exception {
+ TestTask[] expectedTasksList = td.getTypicalTasks();
+ String detailsToEdit = "Bobby p/2 sd/08/04/2017 ed/09/04/2017 t/date";
+ int taskListIndex = 1;
+
+ commandBox.runCommand("clear");
+ commandBox.runCommand(expectedTasksList[0].getAddCommand());
+ TestTask editedTask = new
+ TaskBuilder().withDescription("Bobby")
+ .withPriority("2")
+ .withOccurrences(new ArrayList())
+ .withFrequency(null)
+ .withStartTiming("08/04/2017")
+ .withEndTiming("09/04/2017")
+ .withTags("date")
+ .build();
+
+ assertEditSuccess(taskListIndex, taskListIndex, detailsToEdit,
+ editedTask, expectedTasksList);
+ }
+
+ @Test
+ public void editAllFieldsSepcifiedSuccessForRecurringTask() throws Exception {
+ String detailsToEdit = "Bobby p/2 sd/08/04/2017 ed/09/04/2017 t/date";
+ TestTask taskToEdit = td.recMonth;
+ commandBox.runCommand("clear");
+ commandBox.runCommand(taskToEdit.getAddCommand());
+ commandBox.runCommand("editthis 1 " + detailsToEdit);
+
+ Task editedTask = new Task(new Description("Bobby"), new Priority("2"),
+ new Timing("08/04/2017"), new Timing("09/04/2017"),
+ new UniqueTagList("date"), false, new RecurringFrequency(null));
+
+ TaskCardHandle editedCard = taskListPanel.navigateToTask(editedTask.getDescription().description);
+ assertMatching(editedTask, editedCard);
+
+ commandBox.runCommand("find 01/01/2017");
+ assertResultMessage("0 tasks listed!");
+
+ // Check the first occurrence
+ commandBox.runCommand("find 01/03/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the second occurrence
+ commandBox.runCommand("find 01/05/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the third occurrence
+ commandBox.runCommand("find 01/07/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the fourth occurrence
+ commandBox.runCommand("find 01/09/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the fifth occurrence
+ commandBox.runCommand("find 01/11/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the sixth occurrence
+ commandBox.runCommand("find 01/01/2018");
+ assertResultMessage("1 tasks listed!");
+ }
+
+ @Test
+ public void completeRecurring() throws DuplicateTagException, IllegalValueException {
+ TestTask taskToComplete = td.recMonth;
+ commandBox.runCommand("clear");
+ commandBox.runCommand(taskToComplete.getAddCommand());
+ commandBox.runCommand("complete 1");
+
+ Task editedTask = new Task(taskToComplete.getDescription(), taskToComplete.getPriority(),
+ taskToComplete.getStartTiming(), taskToComplete.getEndTiming(),
+ new UniqueTagList("complete"), false, new RecurringFrequency(null));
+
+ commandBox.runCommand("find 01/01/2017");
+ assertResultMessage("1 tasks listed!");
+ TaskCardHandle editedCard = taskListPanel.navigateToTask(editedTask.getDescription().description);
+ assertMatching(editedTask, editedCard);
+
+ // Check the first occurrence
+ commandBox.runCommand("find 01/03/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the second occurrence
+ commandBox.runCommand("find 01/05/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the third occurrence
+ commandBox.runCommand("find 01/07/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the fourth occurrence
+ commandBox.runCommand("find 01/09/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the fifth occurrence
+ commandBox.runCommand("find 01/11/2017");
+ assertResultMessage("1 tasks listed!");
+
+ // Check the sixth occurrence
+ commandBox.runCommand("find 01/01/2018");
+ assertResultMessage("1 tasks listed!");
+ }
+
+ @Test
+ public void edit_clearTags_success() throws Exception {
+ String detailsToEdit = "t/";
+ int taskListIndex = 1;
+
+ commandBox.runCommand("clear");
+ TestTask[] expectedTasksList = td.getTypicalTasks();
+ for (int i = 0; i < expectedTasksList.length; i++) {
+ commandBox.runCommand(expectedTasksList[i].getAddCommand());
+ }
+ TestTask taskToEdit = expectedTasksList[taskListIndex - 1];
+ TestTask editedTask = new
+ TaskBuilder(taskToEdit).withTags().build();
+
+ assertEditSuccess(taskListIndex, taskListIndex, detailsToEdit,
+ editedTask, expectedTasksList);
+ }
+
+ @Test
+ public void edit_missingPersonIndex_failure() {
+ commandBox.runCommand("clear");
+ TestTask taskToEdit = td.fiona;
+ commandBox.runCommand(taskToEdit.getAddCommand());
+ commandBox.runCommand("edit Bobby");
+ assertResultMessage(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void edit_invalidPersonIndex_failure() {
+ commandBox.runCommand("edit 8 Bobby");
+ assertResultMessage(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void edit_noFieldsSpecified_failure() {
+ commandBox.runCommand("edit 1");
+ assertResultMessage(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
+ /**
+ * Checks whether the edited person has the correct updated details.
+ *
+ * @param filteredTaskListIndex index of person to edit in filtered list
+ * @param taskListIndex index of person to edit in the address book.
+ * Must refer to the same person as {@code filteredPersonListIndex}
+ * @param detailsToEdit details to edit the person with as input to the
+ edit command
+ * @param editedPerson the expected person after editing the person's
+ details
+ */
+ private void assertEditSuccess(int filteredTaskListIndex, int
+ taskListIndex, String detailsToEdit, TestTask editedTask,
+ TestTask[] expectedTasksList) {
+ commandBox.runCommand("edit " + filteredTaskListIndex + " " +
+ detailsToEdit);
+
+ // confirm the new card contains the right data
+ TaskCardHandle editedCard =
+ taskListPanel.navigateToTask(editedTask.getDescription().description);
+ assertMatching(editedTask, editedCard);
+
+ // confirm the list now contains all previous persons plus the person
+ // with updated details
+ expectedTasksList[taskListIndex - 1] = editedTask;
+ assertTrue(taskListPanel.isListMatching(expectedTasksList));
+ assertResultMessage(String.format(EditCommand.MESSAGE_EDIT_TASK_SUCCESS,
+ editedTask));
+ }
+}
+```
+###### /java/guitests/PrioritizeCommandTest.java
+``` java
+package guitests;
+
+import static org.junit.Assert.assertTrue;
+import static seedu.task.logic.commands.PrioritizeCommand.MESSAGE_PRIORITIZE_TASK_SUCCESS;
+
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import guitests.guihandles.TaskCardHandle;
+import seedu.task.TestApp;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.testutil.TaskBuilder;
+import seedu.task.testutil.TestTask;
+
+public class PrioritizeCommandTest extends AddressBookGuiTest {
+ TestTask[] currentList = td.getTypicalTasks();
+
+ @Before
+ public void reset_config() throws IOException {
+ TestApp testApp = new TestApp();
+ Config config = testApp.initConfig(Config.DEFAULT_CONFIG_FILE);
+ ConfigUtil.saveConfig(config, Config.DEFAULT_CONFIG_FILE);
+ commandBox.runCommand("clear");
+ }
+
+ @Test
+ public void prioritizeSuccess() throws IllegalValueException {
+ commandBox.runCommand("clear");
+ for (int i = 0; i < currentList.length; i++) {
+ commandBox.runCommand(currentList[i].getAddCommand());
+ }
+
+ String newPriority = "2";
+ TestTask taskToPrioritize = currentList[0];
+ TestTask prioritizedTask = new TaskBuilder(taskToPrioritize).withPriority(newPriority).build();
+
+ int taskListIndex = 1;
+ assertPrioritizeSuccess(taskListIndex, taskListIndex, "2", prioritizedTask);
+ }
+
+ private void assertPrioritizeSuccess(int taskListIndex, int currentListIndex, String newPriority,
+ TestTask prioritizedTask) {
+ commandBox.runCommand("prioritize " + taskListIndex + " " + newPriority);
+ TaskCardHandle prioritizedCard =
+ taskListPanel.navigateToTask(prioritizedTask.getDescription().toString());
+ assertMatching(prioritizedTask, prioritizedCard);
+
+ currentList[currentListIndex - 1] = prioritizedTask;
+ assertTrue(taskListPanel.isListMatching(currentList));
+ assertResultMessage(String.format(MESSAGE_PRIORITIZE_TASK_SUCCESS, prioritizedTask));
+ }
+}
+```
diff --git a/collated/test/A0163559U.md b/collated/test/A0163559U.md
new file mode 100644
index 000000000000..ba08b673955f
--- /dev/null
+++ b/collated/test/A0163559U.md
@@ -0,0 +1,817 @@
+# A0163559U
+###### /java/guitests/LoadCommandTest.java
+``` java
+package guitests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Optional;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import seedu.task.TestApp;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.exceptions.DataConversionException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.commons.util.FileUtil;
+import seedu.task.logic.commands.LoadCommand;
+import seedu.task.model.task.Task;
+import seedu.task.testutil.TestUtil;
+
+public class LoadCommandTest extends AddressBookGuiTest {
+ private static final String TEST_FOLDER = FileUtil.getPath("./src/test/data/LoadCommandTest/");
+ private static final String TEST_CONFIG_PATH = FileUtil.getPath("./");
+ private static final String TEST_CONFIG = "config.json";
+ private static final String TEST_XML = "changeme.xml";
+ private static final String TEST_SAMPLE_DATA_PATH = TestUtil.getFilePathInSandboxFolder(TEST_XML);
+ private static final String TEST_XML_TO_LOAD = "loadme.xml";
+ private static final String TEST_XML_TO_LOAD_PATH = TEST_FOLDER + TEST_XML_TO_LOAD;
+
+ private static final String LOAD_COMMAND = "load ";
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void reset_config() throws DataConversionException, IOException {
+ //initialize sample data
+ TestUtil.createDataFileWithSampleData(TEST_SAMPLE_DATA_PATH);
+ TestUtil.createDataFileWithSampleData(TestApp.SAVE_LOCATION_FOR_TESTING);
+
+ //create slightly different sample data to later verify successful load
+ ArrayList tasks = new ArrayList(Arrays.asList(TestUtil.SAMPLE_TASK_DATA));
+ tasks.remove(0);
+ TestUtil.createDataFileWithData(TestUtil.generateSampleStorageTaskManager(tasks), TEST_XML_TO_LOAD_PATH);
+
+ Optional opConfig = readConfig(TEST_CONFIG);
+ if (opConfig.isPresent()) {
+ Config config = opConfig.get();
+ config.setTaskManagerFilePath(TEST_FOLDER + TEST_XML);
+ loadConfig(config, TEST_CONFIG);
+ System.out.println("Reset TaskManagerFilePath to " + config.getTaskManagerFilePath());
+ }
+ }
+
+ @Test
+ public void load_success() throws IllegalValueException, DataConversionException, IOException {
+ System.out.println("Testing " + TEST_XML_TO_LOAD_PATH + "...");
+ assertLoadSuccess(TEST_XML_TO_LOAD_PATH);
+ }
+
+ @Test
+ public void load_nullFile_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ thrown.expectMessage(LoadCommand.MESSAGE_NULL_LOAD_LOCATION);
+ LoadCommand sc = new LoadCommand(null);
+ }
+
+ @Test
+ public void load_emptyString_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ thrown.expectMessage(LoadCommand.MESSAGE_NULL_LOAD_LOCATION);
+ LoadCommand sc = new LoadCommand("");
+ }
+
+ @Test
+ public void load_isDirectory_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ thrown.expectMessage(LoadCommand.MESSAGE_DIRECTORY_LOAD_LOCATION);
+ LoadCommand sc = new LoadCommand(TEST_FOLDER);
+ }
+
+ @Test
+ public void load_nonExistentFile_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ String nonExistentFile = "thisisnotafile";
+ thrown.expectMessage(String.format(LoadCommand.MESSAGE_INVALID_LOAD_LOCATION, nonExistentFile));
+ LoadCommand sc = new LoadCommand(nonExistentFile);
+ }
+
+ private void assertLoadSuccess(String expectedFilePath) throws DataConversionException, IOException {
+ System.out.println("before load: " + getFilePathFromConfig());
+
+ commandBox.runCommand(LOAD_COMMAND + expectedFilePath);
+
+ // confirm config file is updated properly
+
+ String actualFilePath = getFilePathFromConfig();
+ System.out.println("after load: " + actualFilePath);
+ System.out.println("expected: " + expectedFilePath);
+ assertEquals(actualFilePath, expectedFilePath);
+
+ // compare old and new task lists
+ File expectedFile = new File(TEST_XML_TO_LOAD_PATH);
+ File actualFile = new File(expectedFilePath);
+ boolean filesMatch = FileUtil.isFileContentSame(expectedFile, actualFile);
+ assertTrue(filesMatch);
+ }
+
+ private String getFilePathFromConfig() throws DataConversionException {
+ Optional opConfig = readConfig(TEST_CONFIG);
+ String configTaskManagerFilePath = "";
+ if (opConfig.isPresent()) {
+ Config config = opConfig.get();
+ configTaskManagerFilePath = config.getTaskManagerFilePath();
+ }
+ return configTaskManagerFilePath;
+ }
+
+ private Optional readConfig(String configFileInTestDataFolder) throws DataConversionException {
+ String configFilePath = addToTestDataPathIfNotNull(configFileInTestDataFolder);
+ return ConfigUtil.readConfig(configFilePath);
+ }
+
+ private void loadConfig(Config config, String configFileInTestDataFolder) throws IOException {
+ String configFilePath = addToTestDataPathIfNotNull(configFileInTestDataFolder);
+ ConfigUtil.saveConfig(config, configFilePath);
+ }
+
+ private String addToTestDataPathIfNotNull(String configFileInTestDataFolder) {
+ return configFileInTestDataFolder != null ? TEST_CONFIG_PATH + configFileInTestDataFolder : null;
+ }
+}
+```
+###### /java/guitests/SaveCommandTest.java
+``` java
+package guitests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Optional;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import seedu.task.TestApp;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.exceptions.DataConversionException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.commons.util.FileUtil;
+import seedu.task.logic.commands.SaveCommand;
+import seedu.task.storage.StorageManager;
+import seedu.task.testutil.TestUtil;
+
+public class SaveCommandTest extends AddressBookGuiTest {
+ private static final String TEST_FOLDER = FileUtil.getPath("./src/test/data/SaveCommandTest/");
+ private static final String TEST_CONFIG_PATH = FileUtil.getPath("./");
+ private static final String TEST_CONFIG = "config.json";
+ private static final String TEST_XML = "changeme.xml";
+ private static final String TEST_SAMPLE_DATA_PATH = TestUtil.getFilePathInSandboxFolder(TEST_XML);
+
+ private static final String SAVE_COMMAND = "save ";
+ private String[] saveFiles = { "blooper", "taskmanager.xml", "data/taskmanager.xml", "data/taskmanager",
+ "taskmanager", "secret_folder/secret_tasks.xml", "secret_folder/secret_tasks" };
+ private String[] saveFiles_Windows = { "blooper", "taskmanager.xml", "data\\taskmanager.xml", "data\\taskmanager",
+ "taskmanager", "secret_folder\\secret_tasks.xml", "secret_folder\\secret_tasks" };
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void reset_config() throws DataConversionException, IOException {
+ // System.out.println("Executing JUnit before!");
+ TestUtil.createDataFileWithSampleData(TEST_SAMPLE_DATA_PATH);
+ TestUtil.createDataFileWithSampleData(TestApp.SAVE_LOCATION_FOR_TESTING);
+
+ Optional opConfig = readConfig(TEST_CONFIG);
+ if (opConfig.isPresent()) {
+ Config config = opConfig.get();
+ config.setTaskManagerFilePath(TEST_FOLDER + TEST_XML);
+ saveConfig(config, TEST_CONFIG);
+ System.out.println("Reset TaskManagerFilePath to " + config.getTaskManagerFilePath());
+ }
+ ((StorageManager) storage).updateXmlTaskListStorage(new File(TEST_SAMPLE_DATA_PATH));
+ }
+
+ @Test
+ public void save_absolute_success() throws IllegalValueException, DataConversionException, IOException {
+ //This test involves saving files with and without extensions, with and without creating new folders
+ //However, all files are prefixed with a specified test folder
+ String[] files = chooseTestStringsByOS();
+ for (String saveFile : files) {
+ System.out.println("Testing " + saveFile + "...");
+ assertSaveSuccess(TEST_FOLDER + saveFile);
+ }
+ }
+
+ private String[] chooseTestStringsByOS() {
+ String os = System.getProperty("os.name");
+ if (os.startsWith("Windows")) {
+ return saveFiles_Windows;
+ } else {
+ return saveFiles;
+ }
+ }
+
+ @Test
+ public void save_relative_success() throws IllegalValueException, DataConversionException, IOException {
+ //This test is similar to the previous, but does not specify the test path.
+ String[] files = chooseTestStringsByOS();
+
+ for (String saveFile : files) {
+ System.out.println("Testing " + saveFile + "...");
+ assertSaveSuccess(saveFile);
+ }
+ }
+
+ @Test
+ public void save_nullFile_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ thrown.expectMessage(SaveCommand.MESSAGE_NULL_SAVE_LOCATION);
+ SaveCommand sc = new SaveCommand(null);
+ }
+
+ @Test
+ public void save_emptyString_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ thrown.expectMessage(SaveCommand.MESSAGE_NULL_SAVE_LOCATION);
+ SaveCommand sc = new SaveCommand("");
+ }
+
+ @Test
+ public void save_isDirectory_illegalValueException() throws IllegalValueException {
+ thrown.expect(IllegalValueException.class);
+ thrown.expectMessage(SaveCommand.MESSAGE_DIRECTORY_SAVE_LOCATION);
+ SaveCommand sc = new SaveCommand(TEST_FOLDER);
+ }
+
+ private void assertSaveSuccess(String expectedFilePath) throws DataConversionException, IOException {
+ System.out.println("before save: " + getFilePathFromConfig());
+
+ commandBox.runCommand(SAVE_COMMAND + expectedFilePath);
+
+ // confirm config file is updated properly
+
+ String actualFilePath = getFilePathFromConfig();
+ System.out.println("after save: " + actualFilePath);
+ System.out.println("expected: " + expectedFilePath);
+ assertEquals(actualFilePath, expectedFilePath);
+
+ // compare old and new task lists
+ File expectedFile = new File(TEST_SAMPLE_DATA_PATH);
+ File actualFile = new File(expectedFilePath);
+ boolean filesMatch = FileUtil.isFileContentSame(expectedFile, actualFile);
+ assertTrue(filesMatch);
+ }
+
+ private String getFilePathFromConfig() throws DataConversionException {
+ Optional opConfig = readConfig(TEST_CONFIG);
+ String configTaskManagerFilePath = "";
+ if (opConfig.isPresent()) {
+ Config config = opConfig.get();
+ configTaskManagerFilePath = config.getTaskManagerFilePath();
+ }
+ return configTaskManagerFilePath;
+ }
+
+ private Optional readConfig(String configFileInTestDataFolder) throws DataConversionException {
+ String configFilePath = addToTestDataPathIfNotNull(configFileInTestDataFolder);
+ return ConfigUtil.readConfig(configFilePath);
+ }
+
+ private void saveConfig(Config config, String configFileInTestDataFolder) throws IOException {
+ String configFilePath = addToTestDataPathIfNotNull(configFileInTestDataFolder);
+ ConfigUtil.saveConfig(config, configFilePath);
+ }
+
+ private String addToTestDataPathIfNotNull(String configFileInTestDataFolder) {
+ return configFileInTestDataFolder != null ? TEST_CONFIG_PATH + configFileInTestDataFolder : null;
+ }
+}
+```
+###### /java/seedu/task/model/task/TaskComparableTest.java
+``` java
+package seedu.task.model.task;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.Test;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.tag.UniqueTagList.DuplicateTagException;
+
+public class TaskComparableTest {
+
+ private String description = "task description ";
+ private String priority = "2";
+ private String timing = "03/03/2017";
+
+ private String tag1 = "friendship";
+ private String tag2 = "love";
+
+ @Test
+ public void sortDescriptions() throws IllegalValueException {
+ Description a = new Description(description + "a");
+ Description b = new Description(description + "b");
+ Description c = new Description(description + "c");
+
+ int ab = a.compareTo(b);
+ assertEquals(ab, -1);
+
+ int ac = a.compareTo(c);
+ assertEquals(ac, -2);
+
+ int ba = b.compareTo(a);
+ assertEquals(ba, 1);
+
+ assertEquals(0, a.compareTo(a));
+
+ ArrayList actual = new ArrayList(Arrays.asList(b, c, a));
+ Collections.sort(actual);
+
+ ArrayList expected = new ArrayList(Arrays.asList(a, b, c));
+
+ assertEquals(actual, expected);
+
+ }
+
+ @Test
+ public void sortPriorities() throws IllegalValueException {
+ Priority a = new Priority("1");
+ Priority b = new Priority("2");
+ Priority c = new Priority("3");
+
+ int ab = a.compareTo(b);
+ assertEquals(ab, -1);
+
+ int ac = a.compareTo(c);
+ assertEquals(ac, -2);
+
+ int ba = b.compareTo(a);
+ assertEquals(ba, 1);
+
+ assertEquals(0, a.compareTo(a));
+
+ ArrayList actual = new ArrayList(Arrays.asList(b, c, a));
+ Collections.sort(actual);
+
+ ArrayList expected = new ArrayList(Arrays.asList(a, b, c));
+
+ assertEquals(actual, expected);
+
+ }
+
+ @Test
+ public void sortTimings() throws IllegalValueException {
+ Timing a = new Timing("01/01/2017");
+ Timing b = new Timing("01/02/2017");
+ Timing c = new Timing("01/03/2017");
+ Timing floatTime = new Timing(null);
+
+ //compare normal Timings
+ int ab = a.compareTo(b);
+ assertEquals(ab, -1);
+
+ int ac = a.compareTo(c);
+ assertEquals(ac, -1);
+
+ int ba = b.compareTo(a);
+ assertEquals(ba, 1);
+
+ assertEquals(0, a.compareTo(a));
+
+ ArrayList actual = new ArrayList(Arrays.asList(b, c, a));
+ Collections.sort(actual);
+
+ ArrayList expected = new ArrayList(Arrays.asList(a, b, c));
+
+ assertEquals(actual, expected);
+
+ //compare null Timings
+
+ int fa = floatTime.compareTo(a);
+ assertEquals(fa, 1);
+
+ int fb = floatTime.compareTo(floatTime);
+ assertEquals(fb, 0);
+
+ int fc = c.compareTo(floatTime);
+ assertEquals(fc, -1);
+
+ //expect null Timing to sort to end of list
+ actual.add(0, floatTime);
+ expected.add(floatTime);
+
+ Collections.sort(actual);
+
+ assertEquals(actual, expected);
+ }
+
+ @Test
+ public void sortTasksByCompleteness() throws DuplicateTagException, IllegalValueException {
+ Timing time = new Timing(timing);
+ UniqueTagList utl = new UniqueTagList(tag1, tag2);
+
+ Task t1 = new Task(new Description(description + "a"), new Priority(priority),
+ time, time, utl, false, null);
+ Task t2 = new Task(new Description(description + "b"), new Priority(priority),
+ time, time, utl, false, null);
+ Task t3 = new Task(new Description(description + "c"), new Priority(priority),
+ time, time, utl, false, null);
+
+ //add two near identical tasks
+ ArrayList al = new ArrayList(Arrays.asList(t1, t2));
+
+ //complete one of them and expect completed task to move to end of list
+ t1.setComplete();
+ sort_and_assertEquals(al, new ArrayList(Arrays.asList(t2, t1)));
+
+ //add an uncompleted task to the end of the list
+ al.add(t3);
+ sort_and_assertEquals(al, new ArrayList(Arrays.asList(t2, t3, t1)));
+
+ //complete a task in the middle and expect it to move to the end
+ t3.setComplete();
+ sort_and_assertEquals(al, new ArrayList(Arrays.asList(t2, t1, t3)));
+
+ //complete a task and expect it to move to the middle
+ t2.setComplete();
+ sort_and_assertEquals(al, new ArrayList(Arrays.asList(t1, t2, t3)));
+ }
+
+ @Test
+ public void sortTasksByCompletenessAndPriority() throws DuplicateTagException, IllegalValueException {
+ Timing time = new Timing(null);
+ UniqueTagList utl = new UniqueTagList(tag1, tag2);
+
+ Task t1 = new Task(new Description(description + "a t1"), new Priority("1"),
+ time, time, utl, false, null);
+ Task t2 = new Task(new Description(description + "b t2"), new Priority("1"),
+ time, time, utl, false, null);
+ Task t3 = new Task(new Description(description + "c t3"), new Priority("1"),
+ time, time, utl, false, null);
+ Task t4 = new Task(new Description(description + "a t4"), new Priority("2"),
+ time, time, utl, false, null);
+ Task t5 = new Task(new Description(description + "b t5"), new Priority("2"),
+ time, time, utl, false, null);
+ Task t6 = new Task(new Description(description + "c t6"), new Priority("2"),
+ time, time, utl, false, null);
+ Task t7 = new Task(new Description(description + "a t7"), new Priority("3"),
+ time, time, utl, false, null);
+ Task t8 = new Task(new Description(description + "b t8"), new Priority("3"),
+ time, time, utl, false, null);
+ Task t9 = new Task(new Description(description + "c t9"), new Priority("3"),
+ time, time, utl, false, null);
+
+ //expect tasks to sort by priority, then by description
+ ArrayList actual = new ArrayList(Arrays.asList(t9, t8, t7, t6, t5, t4, t3, t2, t1));
+ ArrayList expected = new ArrayList(Arrays.asList(t1, t2, t3, t4, t5, t6, t7, t8, t9));
+ sort_and_assertEquals(actual, expected);
+
+ t1.setComplete();
+ t4.setComplete();
+ t7.setComplete();
+
+ //expect tasks to sort by complete, then priority, then description
+ expected = new ArrayList(Arrays.asList(t2, t3, t5, t6, t8, t9, t1, t4, t7));
+ sort_and_assertEquals(actual, expected);
+ Task t2et = new Task(new Description(description + "b t2et"), new Priority("1"),
+ time, new Timing("01/01/2017"), utl, false, null);
+ Task t5et = new Task(new Description(description + "b t5et"), new Priority("2"),
+ time, new Timing("01/02/2017"), utl, false, null);
+ Task t8et = new Task(new Description(description + "b t8et"), new Priority("3"),
+ time, new Timing("01/03/2017"), utl, false, null);
+
+ actual.add(t2et);
+ actual.add(t5et);
+ actual.add(t8et);
+
+ //expect tasks to sort by complete, then end timing, priority, description
+ expected = new ArrayList(Arrays.asList(t2et, t2, t3, t5et, t5, t6, t8et,
+ t8, t9, t1, t4, t7));
+ sort_and_assertEquals(actual, expected);
+
+ }
+
+ private void sort_and_assertEquals(ArrayList actual, ArrayList expected) {
+ Collections.sort(actual);
+ printDescriptions(actual);
+ assertEquals(actual, expected);
+ }
+
+ private void printDescriptions(ArrayList al) {
+ System.out.println("Starting print...");
+ for (Task t : al) {
+ System.out.print(t.getPriority() + " " + t.getDescription() +
+ " " + t.getEndTiming());
+ if (t.isComplete()) {
+ System.out.print(" complete");
+ }
+ System.out.println();
+ }
+ System.out.println("Ending print.");
+
+ }
+}
+```
+###### /java/seedu/task/testutil/TaskBuilder.java
+``` java
+/**
+ * A class for building mutable task objects. For testing only.
+ */
+public class TaskBuilder {
+
+ private TestTask task;
+
+ public TaskBuilder() {
+ this.task = new TestTask();
+ }
+
+ /**
+ * Initializes the TaskBuilder with the data of {@code taskToCopy}.
+ */
+ public TaskBuilder(TestTask taskToCopy) {
+ this.task = new TestTask(taskToCopy);
+ }
+
+ public TaskBuilder withDescription(String description) throws IllegalValueException {
+ this.task.setDescription(new Description(description));
+ return this;
+ }
+
+ public TaskBuilder withPriority(String priority) throws IllegalValueException {
+ this.task.setPriority(new Priority(priority));
+ return this;
+ }
+
+ public TaskBuilder withOccurrences(ArrayList occurrences) throws IllegalValueException {
+ this.task.setOccurrences(occurrences);
+ this.task.getOccurrences().add(new RecurringTaskOccurrence());
+ return this;
+ }
+
+ public TaskBuilder withRecurring(boolean isRecurring) throws IllegalValueException {
+ this.task.setRecurring(isRecurring);
+ return this;
+ }
+
+ public TaskBuilder withTags(String ... tags) throws IllegalValueException {
+ task.setTags(new UniqueTagList());
+ for (String tag: tags) {
+ task.getTags().add(new Tag(tag));
+ }
+ return this;
+ }
+
+ public TaskBuilder withFrequency(String frequency) throws IllegalValueException {
+ this.task.setFrequency(new RecurringFrequency(frequency));
+ return this;
+ }
+
+ public TaskBuilder withOccurrenceIndexList(ArrayList occurrenceIndexList) throws IllegalValueException {
+ this.task.setOccurrenceIndexList(occurrenceIndexList);
+ return this;
+ }
+
+ public TaskBuilder withStartTiming(String string) throws IllegalValueException {
+ this.task.setStartTiming(new Timing(string));
+ return this;
+ }
+
+ public TaskBuilder withEndTiming(String string) throws IllegalValueException {
+ this.task.setEndTiming(new Timing(string));
+ return this;
+ }
+
+ public TestTask build() {
+ return this.task;
+ }
+
+}
+```
+###### /java/seedu/task/testutil/TestTask.java
+``` java
+/**
+ * A mutable Task object. For testing only.
+ */
+public class TestTask implements ReadOnlyTask {
+
+ private Description description;
+ private Priority priority;
+ private ArrayList occurrences;
+ private boolean recurring;
+ private UniqueTagList tags;
+ private RecurringFrequency frequency;
+ private ArrayList occurrenceIndexList = new ArrayList();
+
+ public TestTask() {
+ tags = new UniqueTagList();
+ }
+
+ /**
+ * Creates a copy of {@code taskToCopy}.
+ */
+ public TestTask(TestTask taskToCopy) {
+ this.description = taskToCopy.getDescription();
+ this.priority = taskToCopy.getPriority();
+ this.occurrences = taskToCopy.getOccurrences();
+ this.recurring = taskToCopy.isRecurring();
+ this.tags = taskToCopy.getTags();
+ this.frequency = taskToCopy.getFrequency();
+ this.occurrenceIndexList = taskToCopy.getOccurrenceIndexList();
+ }
+
+ public void setDescription(Description description) {
+ this.description = description;
+ }
+
+ public void setPriority(Priority priority) {
+ this.priority = priority;
+ }
+
+ public void setOccurrences(ArrayList occurrences) {
+ this.occurrences = occurrences;
+ }
+
+ @Override
+ public void setRecurring(boolean isRecurring) {
+ this.recurring = isRecurring;
+ }
+
+ public void setTags(UniqueTagList tags) {
+ this.tags = tags;
+ }
+
+ @Override
+ public void setFrequency(RecurringFrequency recurringFrequency) {
+ this.frequency = recurringFrequency;
+ }
+
+ @Override
+ public void setOccurrenceIndexList(ArrayList list) {
+ occurrenceIndexList = list;
+ }
+
+ @Override
+ public Description getDescription() {
+ return description;
+ }
+
+ @Override
+ public Priority getPriority() {
+ return priority;
+ }
+
+ @Override
+ public ArrayList getOccurrences() {
+ return occurrences;
+ }
+
+ @Override
+ public boolean isRecurring() {
+ return recurring;
+ }
+
+ @Override
+ public UniqueTagList getTags() {
+ return tags;
+ }
+
+ @Override
+ public RecurringFrequency getFrequency() {
+ return frequency;
+ }
+
+ @Override
+ public ArrayList getOccurrenceIndexList() {
+ return occurrenceIndexList;
+ }
+
+ @Override
+ public void setStartTiming(Timing startTiming) {
+ assert startTiming != null;
+ this.occurrences.get(0).setStartTiming(startTiming);
+ }
+
+ @Override
+ public void setEndTiming(Timing endTiming) {
+ assert endTiming != null;
+ this.occurrences.get(0).setEndTiming(endTiming);
+ }
+
+ public void setComplete(boolean complete) {
+ this.occurrences.get(0).setComplete(true);
+ }
+
+ @Override
+ public Timing getStartTiming() {
+ return getStartTiming(0);
+ }
+
+ @Override
+ public Timing getStartTiming(int i) {
+ return this.occurrences.get(i).getStartTiming();
+ }
+
+ @Override
+ public Timing getEndTiming() {
+ return this.occurrences.get(0).getEndTiming();
+ }
+
+ @Override
+ public boolean isComplete() {
+ return this.occurrences.get(0).isComplete();
+
+ }
+
+ @Override
+ public String toString() {
+ return getAsText();
+ }
+
+ // TODO add complete instance variable?
+ public String getAddCommand() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("add " + this.getDescription().description + " ");
+ sb.append("p/" + this.getPriority().value + " ");
+ sb.append("sd/" + this.getStartTiming().value + " ");
+ sb.append("ed/" + this.getEndTiming().value + " ");
+ if (this.isRecurring()) {
+ sb.append("r/" + this.getFrequency().frequency + " ");
+ }
+ this.getTags().asObservableList().stream().forEach(s -> sb.append("t/" + s.tagName + " "));
+ return sb.toString();
+ }
+
+ @Override
+ public void removeOccurrence(int i) {
+ this.occurrences.remove(i);
+ }
+
+}
+```
+###### /java/seedu/task/testutil/TestUtil.java
+``` java
+ private static Task[] getSampleTaskData() {
+ try {
+ return new Task[]{
+ new Task(new Description("Ali Muster"), new Priority("1"), new Timing("02/02/2017"),
+ new Timing("02/02/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Boris Mueller"), new Priority("2"), new Timing("02/03/2017"),
+ new Timing("02/03/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Carl Kurz"), new Priority("3"), new Timing("02/04/2017"),
+ new Timing("02/04/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Daniel Meier"), new Priority("1"), new Timing("02/05/2017"),
+ new Timing("02/05/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Elle Meyer"), new Priority("2"), new Timing("02/06/2017"),
+ new Timing("02/06/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Fiona Kunz"), new Priority("2"), new Timing("02/07/2017"),
+ new Timing("02/07/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("George Best"), new Priority("2"), new Timing("02/08/2017"),
+ new Timing("02/08/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Hoon Meier"), new Priority("2"), new Timing("02/09/2017"),
+ new Timing("02/09/2017"), new UniqueTagList(), false, new RecurringFrequency(null)),
+ new Task(new Description("Ida Mueller"), new Priority("2"), new Timing("02/02/2017"),
+ new Timing("02/02/2017"), new UniqueTagList(), false, new RecurringFrequency(null))
+ };
+ } catch (IllegalValueException e) {
+ return null;
+ }
+ }
+```
+###### /java/seedu/task/testutil/TestUtil.java
+``` java
+ public static XmlSerializableTaskList generateSampleStorageTaskManager() {
+ TaskList tl = new TaskList();
+ for (Task t : SAMPLE_TASK_DATA) {
+ try {
+ tl.addTask(t);
+ } catch (DuplicateTaskException e) {
+ //continue
+ }
+ }
+ return new XmlSerializableTaskList(tl);
+ }
+
+ //assists with load command test
+ public static XmlSerializableTaskList generateSampleStorageTaskManager(ArrayList tasks) {
+ TaskList tl = new TaskList();
+ for (Task t : tasks) {
+ try {
+ tl.addTask(t);
+ } catch (DuplicateTaskException e) {
+ //continue
+ }
+ }
+ return new XmlSerializableTaskList(tl);
+ }
+```
diff --git a/collated/test/A0163935X.md b/collated/test/A0163935X.md
new file mode 100644
index 000000000000..c39f2df2a9da
--- /dev/null
+++ b/collated/test/A0163935X.md
@@ -0,0 +1,349 @@
+# A0163935X
+###### /java/guitests/AddCommandTest.java
+``` java
+ private void assertAddSuccess(TestTask taskToAdd, TestTask... currentList) throws IllegalValueException {
+ commandBox.runCommand("clear");
+ for (int i = 0; i < currentList.length; i++) {
+ commandBox.runCommand(currentList[i].getAddCommand());
+ }
+ commandBox.runCommand(taskToAdd.getAddCommand());
+
+ // confirm the new card contains the right data
+ TaskCardHandle addedCard = taskListPanel.navigateToTask(taskToAdd.getDescription().toString());
+ assertMatching(taskToAdd, addedCard);
+
+
+ // confirm the list now contains all previous tasks plus the new task
+ TestTask[] expectedList = TestUtil.addTasksToList(currentList, taskToAdd);
+ assertTrue(taskListPanel.isListMatching(expectedList));
+ }
+
+```
+###### /java/guitests/CalenderCommandTest.java
+``` java
+package guitests;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Calendar;
+
+import org.junit.Test;
+
+public class CalenderCommandTest extends AddressBookGuiTest {
+ @Test
+ public void checkToday() {
+ Calendar calendar = Calendar.getInstance();
+ int dayOfToday = calendar.getTime().getDay() + 1;
+ boolean dateOfTodayIsCorrect = false;
+ for (int i = 1; i <= 7; i++) {
+ String dateOfIthLabel = calenderPanel.getDateOfIthLabel(i);
+ if (dateOfIthLabel.equals((String.valueOf(calendar.getTime().getMonth() + 1) +
+ "/" + String.valueOf(calendar.getTime().getDate()))) && i == dayOfToday) {
+ dateOfTodayIsCorrect = true;
+ }
+ }
+ assertTrue(dateOfTodayIsCorrect);
+
+ }
+ // @Test
+ // public void checkTask() {
+ // commandBox.runCommand("add
+ // Say so long to Fiona Kunz p/1 sd/01/02/2017 ed/02/03/2100 r/0 t/owesMoney t/friends");
+ // System.out.println("@@"+taskListPanel.getListView().getItems().get(0));
+ //
+ // String dateOfIthLabel=calenderPanel.getDateOfIthLabel(1);
+ // commandBox.runCommand("add timeOrderTest sd/02/04/2017 11:00 ed/02/04/2017 12:00");
+ // commandBox.runCommand("add asd sd/02/04/2017 11:00 ed/02/04/2017 12:00");
+ // System.out.println("@@"+taskListPanel.getListView().getItems().get(1));
+ // //
+ // System.out.println("@@"+taskListPanel.getListView().getItems().size());
+ // Calendar calendar = Calendar.getInstance();
+ // int dayOfToday=calendar.getTime().getDay()+1;
+ // System.out.println(dateOfIthLabel);
+ // boolean TaskExistCorrectly=false;
+ // for(int i=1;i<=28;i++)
+ // System.out.println("##"+calenderPanel.getListView(i).getItems());
+ // // for(int i=0;i getListView(int i) {
+ return getNode(PERSON_LIST_VIEW_ID + i);
+ }
+
+ public String getDateOfIthLabel(int i) {
+ return getLabelText("#day" + i);
+ }
+
+}
+```
+###### /java/guitests/guihandles/GuiHandle.java
+``` java
+ protected ObservableList getListviewTask(String filedName) {
+ ListView listview = getNode(filedName);
+ System.out.println("@@" + listview.getItems());
+ for (int i = 1; i <= 28; i++) {
+ listview = getNode("#listview1");
+ System.out.println("!!" + listview);
+ System.out.println("!!" + listview.getItems());
+ }
+ guiRobot.sleep(2000);
+ return listview.getItems();
+ }
+ protected String getLabelText(String filedName) {
+ Label label = getNode(filedName);
+ return label.getText();
+ }
+```
+###### /java/guitests/guihandles/GuiHandle.java
+``` java
+ protected String getTextFieldText(String filedName) {
+ TextField textField = getNode(filedName);
+ return textField.getText();
+ }
+
+ protected void setTextField(String textFieldId, String newText) {
+ guiRobot.clickOn(textFieldId);
+ TextField textField = getNode(textFieldId);
+ textField.setText(newText);
+ guiRobot.sleep(500); // so that the texts stays visible on the GUI for a short period
+ }
+
+ public void pressEnter() {
+ guiRobot.type(KeyCode.ENTER).sleep(500);
+ }
+
+ protected String getTextFromLabel(String fieldId, Node parentNode) {
+ return ((Label) guiRobot.from(parentNode).lookup(fieldId).tryQuery().get()).getText();
+ }
+
+ public void focusOnSelf() {
+ if (stageTitle != null) {
+ focusOnWindow(stageTitle);
+ }
+ }
+
+ public void focusOnMainApp() {
+ this.focusOnWindow(TestApp.APP_TITLE);
+ }
+
+ public void closeWindow() {
+ Optional window = guiRobot.listTargetWindows()
+ .stream()
+ .filter(w -> w instanceof Stage && ((Stage) w).getTitle().equals(stageTitle)).findAny();
+
+ if (!window.isPresent()) {
+ return;
+ }
+
+ guiRobot.targetWindow(window.get());
+ guiRobot.interact(() -> ((Stage) window.get()).close());
+ focusOnMainApp();
+ }
+}
+```
diff --git a/collated/test/A0164212U.md b/collated/test/A0164212U.md
new file mode 100644
index 000000000000..d7c5259f0172
--- /dev/null
+++ b/collated/test/A0164212U.md
@@ -0,0 +1,262 @@
+# A0164212U
+###### /java/guitests/AddCommandTest.java
+``` java
+ //
+ // //invalid timing order
+ //start date = end date (start time > end time)
+ commandBox.runCommand("add timeOrderTest sd/11:45 ed/10:45");
+ assertResultMessage(Messages.MESSSAGE_INVALID_TIMING_ORDER);
+ //start date > end date (same time)
+ commandBox.runCommand("add timeOrderTest sd/10:45 26/03/2017 ed/10:45 25/03/2016");
+ assertResultMessage(Messages.MESSSAGE_INVALID_TIMING_ORDER);
+ //start date > end date (no time)
+ commandBox.runCommand("add timeOrderTest sd/03/08/2017 ed/25/03/2016");
+ assertResultMessage(Messages.MESSSAGE_INVALID_TIMING_ORDER);
+ //start date > end date (start time > end time)
+ commandBox.runCommand("add timeOrderTest sd/10:45 01/01/2017 ed/09:45 01/01/2016");
+ assertResultMessage(Messages.MESSSAGE_INVALID_TIMING_ORDER);
+ //start date > end date (start time < end time)
+ commandBox.runCommand("add timeOrderTest sd/08:45 05/06/2012 ed/09:45 02/05/2012");
+ assertResultMessage(Messages.MESSSAGE_INVALID_TIMING_ORDER);
+ // //invalid syntax for timing
+ commandBox.runCommand("add timeSyntaxTest sd/1:45");
+ assertResultMessage(Timing.MESSAGE_TIMING_CONSTRAINTS);
+ //should be 01:45
+ commandBox.runCommand("add timeSyntaxTest sd/01:45 1/01/2017");
+ assertResultMessage(Timing.MESSAGE_TIMING_CONSTRAINTS);
+ //should be 01/01/2017 for date
+ commandBox.runCommand("add timeSyntaxTest sd/01:45 01/01/2017 ed/3:15 01/01/2017");
+ assertResultMessage(Timing.MESSAGE_TIMING_CONSTRAINTS);
+ //should be 03:15
+ commandBox.runCommand("add timeSyntaxTest sd/01:45 01/01/2017 ed/03:15 01/2/2017");
+ assertResultMessage(Timing.MESSAGE_TIMING_CONSTRAINTS);
+ //should be 01/02/2017
+```
+###### /java/guitests/AddCommandTest.java
+``` java
+ //test daily recurring tasks
+ taskToAdd = td.recDay;
+ assertAddSuccess(taskToAdd, currentList);
+ currentList = TestUtil.addTasksToList(currentList, taskToAdd);
+ assertTrue(taskListPanel.isListMatching(currentList));
+ ArrayList hardCodedDay = new ArrayList();
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("01/05/2017"), new Timing("01/05/2017")));
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("11/05/2017"), new Timing("11/05/2017")));
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("21/05/2017"), new Timing("21/05/2017")));
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("31/05/2017"), new Timing("31/05/2017")));
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("10/06/2017"), new Timing("10/06/2017")));
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("20/06/2017"), new Timing("20/06/2017")));
+ hardCodedDay.add(new RecurringTaskOccurrence(new Timing("30/06/2017"), new Timing("30/06/2017")));
+ Task taskDay = new Task(taskToAdd.getDescription(), taskToAdd.getPriority(),
+ taskToAdd.getStartTiming(), taskToAdd.getEndTiming(), taskToAdd.getTags(),
+ taskToAdd.isRecurring(), taskToAdd.getFrequency());
+ assertOccurrenceSame(hardCodedDay, taskDay.getOccurrences());
+
+ //test yearly recurring tasks
+ taskToAdd = td.recYear;
+ assertAddSuccess(taskToAdd, currentList);
+ currentList = TestUtil.addTasksToList(currentList, taskToAdd);
+ assertTrue(taskListPanel.isListMatching(currentList));
+ ArrayList hardCodedYear = new ArrayList();
+ hardCodedYear.add(new RecurringTaskOccurrence(new Timing("25/07/2017"), new Timing("25/07/2017")));
+ hardCodedYear.add(new RecurringTaskOccurrence(new Timing("25/07/2018"), new Timing("25/07/2018")));
+ hardCodedYear.add(new RecurringTaskOccurrence(new Timing("25/07/2019"), new Timing("25/07/2019")));
+ hardCodedYear.add(new RecurringTaskOccurrence(new Timing("25/07/2020"), new Timing("25/07/2020")));
+ Task taskYear = new Task(taskToAdd.getDescription(), taskToAdd.getPriority(),
+ taskToAdd.getStartTiming(), taskToAdd.getEndTiming(), taskToAdd.getTags(),
+ taskToAdd.isRecurring(), taskToAdd.getFrequency());
+ assertOccurrenceSame(hardCodedYear, taskYear.getOccurrences());
+
+ // //invalid add command for recurring task
+ //missing end time
+ commandBox.runCommand("add inValidRecTask sd/01/01/2017 r/2m");
+ assertResultMessage(Task.MESSAGE_MISSING_TIMING);
+ //missing start time
+ commandBox.runCommand("add inValidRecTask ed/05/11/2018 r/1y");
+ assertResultMessage(Task.MESSAGE_MISSING_TIMING);
+```
+###### /java/seedu/task/model/task/DescriptionTest.java
+``` java
+package seedu.task.model.task;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class DescriptionTest {
+
+ @Test
+ public void isValidDescription() {
+ // invalid name
+ assertFalse(Description.isValidDescription("")); // empty string
+ assertFalse(Description.isValidDescription(" ")); // spaces only
+ // valid name
+ assertTrue(Description.isValidDescription("finish homework")); // alphabets only
+ assertTrue(Description.isValidDescription("this is a very long task that must be finished soon"));
+ // long frequency
+ assertTrue(Description.isValidDescription("Capitalize The Description")); // with capital letters
+ assertTrue(Description.isValidDescription("2564")); // numbers only
+ assertTrue(Description.isValidDescription("task1")); // contains numbers characters at end
+ assertTrue(Description.isValidDescription("21task")); // contains numbers characters at beginning
+ assertTrue(Description.isValidDescription("task@")); // contains non-alphanumeric characters at end
+ }
+}
+```
+###### /java/seedu/task/model/task/PriorityTest.java
+``` java
+package seedu.task.model.task;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class PriorityTest {
+
+ @Test
+ public void isValidPriority() {
+ // invalid priorities
+ assertFalse(Priority.isValidPriority("")); // empty string
+ assertFalse(Priority.isValidPriority(" ")); // spaces only
+ assertFalse(Priority.isValidPriority("4")); // boundary case
+ assertFalse(Priority.isValidPriority("0")); // boundary case
+ assertFalse(Priority.isValidPriority("2alpha")); // valid priority followed by alpha characters
+ assertFalse(Priority.isValidPriority("2 alpha")); // valid priority followed by alpha char separated by space
+ assertFalse(Priority.isValidPriority("01")); // no leading 0
+
+ // valid priorities
+ assertTrue(Priority.isValidPriority("1")); // boundary case
+ assertTrue(Priority.isValidPriority("3")); // boundary case
+ }
+}
+```
+###### /java/seedu/task/model/task/RecurringFrequencyTest.java
+``` java
+package seedu.task.model.task;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class RecurringFrequencyTest {
+
+ @Test
+ public void isValidFrequency() {
+ // invalid frequency
+ assertFalse(RecurringFrequency.isValidFrequency("")); // empty string
+ assertFalse(RecurringFrequency.isValidFrequency(" ")); // spaces only
+ assertFalse(RecurringFrequency.isValidFrequency("2malpha")); // valid priority followed by alpha characters
+ assertFalse(RecurringFrequency.isValidFrequency("2y alpha"));
+ // valid priority followed by alpha char separated by space
+ assertFalse(RecurringFrequency.isValidFrequency(".1y")); // decimal year
+ assertFalse(RecurringFrequency.isValidFrequency(".1d")); // decimal day
+ assertFalse(RecurringFrequency.isValidFrequency(".1m")); // decimal month
+
+ // valid frequency
+ assertTrue(RecurringFrequency.isValidFrequency("1y")); // one digit year
+ assertTrue(RecurringFrequency.isValidFrequency("10y")); // two digit year
+ assertTrue(RecurringFrequency.isValidFrequency("1d")); // one digit day
+ assertTrue(RecurringFrequency.isValidFrequency("10d")); // two digit day
+ assertTrue(RecurringFrequency.isValidFrequency("1m")); // one digit month
+ assertTrue(RecurringFrequency.isValidFrequency("10m")); // two digit month
+ }
+
+}
+```
+###### /java/seedu/task/model/task/TimingTest.java
+``` java
+package seedu.task.model.task;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+
+public class TimingTest {
+
+
+ @Test
+ public void isValidTiming() throws IllegalValueException {
+ // // blank timing
+ assertFalse(Timing.isValidTiming("")); // empty string
+ assertFalse(Timing.isValidTiming(" ")); // spaces only
+ //
+ // // missing parts ("dd/MM/yyyy")
+ assertFalse(Timing.isValidTiming("05/2017")); // missing day
+ assertFalse(Timing.isValidTiming("31/2017")); // missing month
+ assertFalse(Timing.isValidTiming("05/30")); // missing year
+ // // missing parts ("HH:mm dd/MM/yyyy")
+ assertFalse(Timing.isValidTiming(":25 02/03/2018")); // missing hour
+ assertFalse(Timing.isValidTiming("12 02/03/2018")); // missing minute
+ assertFalse(Timing.isValidTiming("12:25 03/2018")); // missing day
+ assertFalse(Timing.isValidTiming("12:25 02/2018")); // missing month
+ assertFalse(Timing.isValidTiming("12:25 02/03")); // missing year
+ // // missing parts ("HH:mm")
+ assertFalse(Timing.isValidTiming("05")); // missing minute
+ assertFalse(Timing.isValidTiming(":15")); // missing hour
+ //
+ // // invalid parts ("dd/MM/yyyy")
+ assertFalse(Timing.isValidTiming("00/06/2017")); // invalid day (boundary case)
+ assertFalse(Timing.isValidTiming("32/01/2017")); // invalid day (boundary case)
+ assertFalse(Timing.isValidTiming("29/02/2017")); // invalid day (non-leap year)
+ assertFalse(Timing.isValidTiming("10/00/2017")); // invalid month (boundary case)
+ assertFalse(Timing.isValidTiming("10/13/2017")); // invalid month (boundary case)
+ assertFalse(Timing.isValidTiming("05/12/999")); // invalid year (boundary case)
+ assertFalse(Timing.isValidTiming("05/12/10000")); // invalid year (boundary case)
+ assertFalse(Timing.isValidTiming("05.12.2017")); // invalid symbol
+ assertFalse(Timing.isValidTiming("05/12/20175")); // invalid year
+ // assertFalse(Timing.isValidTiming("05/12/2017@")); // invalid symbol
+ // // invalid parts ("HH:mm dd/MM/yyyy")
+ assertFalse(Timing.isValidTiming("15:30 00/06/2017")); // invalid day (boundary case)
+ assertFalse(Timing.isValidTiming("15:30 32/01/2017")); // invalid day (boundary case)
+ assertFalse(Timing.isValidTiming("15:30 10/00/2017")); // invalid month (boundary case)
+ assertFalse(Timing.isValidTiming("15:30 10/13/2017")); // invalid month(boundary case)
+ assertFalse(Timing.isValidTiming("15:30 29/02/2017")); // invalid day (non-leap year)
+ assertFalse(Timing.isValidTiming("24:30 05/12/2017")); // invalid hour (boundary case)
+ assertFalse(Timing.isValidTiming("-01:30 05/12/2017")); // invalid hour (boundary case)
+ assertFalse(Timing.isValidTiming("15:60 05/12/999")); // invalid year (boundary case)
+ assertFalse(Timing.isValidTiming("15:60 05/12/10000")); // invalid year (boundary case)
+ assertFalse(Timing.isValidTiming("15:60 05/12/2017")); // invalid minute (boundary case)
+ assertFalse(Timing.isValidTiming("15:-10 05/12/2017")); // invalid minute (boundary case)
+ assertFalse(Timing.isValidTiming("05:45 05.12.2017")); // invalid symbol
+ assertFalse(Timing.isValidTiming("05.45 05/12/2017")); // invalid symbol
+ // assertFalse(Timing.isValidTiming("8:36 05/12/2017@")); // invalid symbol
+ //
+ // // valid timing ("dd/MM/yyyy")
+ assertTrue(Timing.isValidTiming("29/02/2016")); // valid leap year
+ assertTrue(Timing.isValidTiming("31/07/2016")); // boundary case for day
+ assertTrue(Timing.isValidTiming("01/08/2016")); // boundary case for day
+ assertTrue(Timing.isValidTiming("30/06/2016")); // boundary case for day
+ assertTrue(Timing.isValidTiming("05/01/2019")); // boundary case for month
+ assertTrue(Timing.isValidTiming("15/12/2016")); // boundary case for month
+ assertTrue(Timing.isValidTiming("17/10/1000")); // boundary case for year
+ assertTrue(Timing.isValidTiming("15/11/9999")); // boundary case for year
+ assertTrue(Timing.isValidTiming("14/09/2020")); // random, "normal" date (no boundary parameter)
+ // // valid timing ("HH:mm dd/MM/yyyy")
+ assertTrue(Timing.isValidTiming("06:35 29/02/2016")); // valid leap year
+ assertTrue(Timing.isValidTiming("06:35 31/07/2016")); // boundary case for day
+ assertTrue(Timing.isValidTiming("07:56 01/08/2016")); // boundary case for day
+ assertTrue(Timing.isValidTiming("20:39 30/06/2016")); // boundary case for day
+ assertTrue(Timing.isValidTiming("03:34 05/01/2019")); // boundary case for month
+ assertTrue(Timing.isValidTiming("02:15 15/12/2016")); // boundary case for month
+ assertTrue(Timing.isValidTiming("05:15 17/10/1000")); // boundary case for year
+ assertTrue(Timing.isValidTiming("06:25 15/11/9999")); // boundary case for year
+ assertTrue(Timing.isValidTiming("13:16 14/09/2020")); // random, "normal" date (no boundary parameter)
+ assertTrue(Timing.isValidTiming("00:15 14/09/2020")); // boundary case for hour
+ assertTrue(Timing.isValidTiming("23:15 14/09/2020")); // boundary case for hour
+ assertTrue(Timing.isValidTiming("10:00 14/09/2020")); // boundary case for minute
+ assertTrue(Timing.isValidTiming("15:59 14/09/2020")); // boundary case for minute
+ assertTrue(Timing.isValidTiming("00:00 14/09/2020")); // boundary case for hour and minute
+ //
+ // // valid timing (only "HH:mm" given) - Should not throw IllegalValueException
+ new Timing("00:15"); // boundary case for hour
+ new Timing("23:15"); // boundary case for hour
+ new Timing("12:00"); // boundary case for minute
+ new Timing("12:59"); // boundary case for minute
+ }
+}
+```
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 8d2010e02e38..6b4d5d1dd5b3 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -4,49 +4,84 @@ 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
+#### [Jay Gajendra Kabra](https://github.com/jay500s)
+
+* Components in Charge of: [Model](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/DeveloperGuide.md#24-model-component)
+* Aspects/tools in charge of: Code Quality
+* Features implemented:
+ * [Recurring Tasks](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#3-notes-on-recurring-tasks) - Full stack implementation
+ * [Find on any parameter](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#25-finding-all-tasks-containing-any-keyword-in-their-name-find)
+ * [Prioritize Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#28-allocate-priority-to-a-task-prioritize) - Worked with Heyang to implement logic and model functionality
+* Code written:
+ * [Functional code](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/collated/main/A0164212U.md)
+ * [Test code](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/collated/test/A0164212U.md)
+* Other major contributions:
+ * Initial refactoring from AddressBook to Task Manager
+ * Created Description, Priority, and Timing classes and added respective functionality to validate respective parameters
+ * Colored Priorities for better UI experience
+ * Debugged test code classes when testing recurring tasks
+ * Significant contributions to User Guide for almost all commands, descriptions, and examples
-----
-#### [Joshua Lee](http://github.com/lejolly)
-
+#### [Tyler Austin Rocha](https://github.com/tylerrocha)
+
Role: Developer
-Responsibilities: UI
+Responsibilities: Storage, GitHub
+* Components in Charge of: [Storage](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/DeveloperGuide.md#25-storage-component)
+* Features implemented:
+ * [Comparable Tasks](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#231-natural-ordering-of-tasks)
+ * [Save Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#211-saving-the-data--save)
+ * [Load Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#212-loading-the-data--load)
+* Code written: [[Functional code](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/collated/main/A0163559U.md)][[Test code](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/collated/test/A0163559U.md)]
+* Other major contributions:
+ * Maintained storage, comparable, save/load, logic manager and XMLUtil tests
+ * Updated testutil files, e.g. TestTask and TaskBuilder
+ * Tracked down and fixed general bugs such as null pointer on exit command
+ * Maintained git repo, git page; set up Travis, Appveyor, Codacy, Coveralls
+ * Provided assistance with Eclipse, Sublime Text features
------
-
-#### [Leow Yijin](http://github.com/yijinl)
-
-Role: Developer
-Responsibilities: Data
-----
-#### [Martin Choo](http://github.com/m133225)
-
+#### [Wu Heyang](https://github.com/whyCaiJi)
+
Role: Developer
-Responsibilities: Dev Ops
+Responsibilities: Logic and Scheduling and Tracking
+* Component in Charge of: [Logic](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/DeveloperGuide.md#23-logic-component)
+* Features implemented:
+ * [Adding floating task](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#22-adding-a-task-add)
+ * [Complete Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#27-complete-a-task--complete)
+ * [Prioritize Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/UserGuide.md#28-allocate-priority-to-a-task-prioritize)
+ * [Undo Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/final_stuff/docs/UserGuide.md#213-revert-the-previous-change--undo)
+ * [Redo Command](https://github.com/CS2103JAN2017-T11-B3/main/blob/final_stuff/docs/UserGuide.md#214-revert-the-previous-undo-change-redo)
+* Code written: [[Functional code](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/collated/main/A0113795Y.md)][[Test code](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/collated/test/A0113795Y.md)]
+* Other major contributions:
+ * Refactored commands class files to align with Task Manager context
+ * Wrote test cases for GUI tests
+ * Implemented edit and delete command on single occurrence of a recurring task
+ * Modified ModelManager.java to align with features
-----
-#### [Thien Nguyen](https://github.com/ndt93)
- Role: Developer
- Responsibilities: Threading
+#### [Yu Cheng-Liang](https://github.com/nuslarry)
+
+*Components in Charge of: [UI](https://github.com/CS2103JAN2017-T11-B3/main/blob/master/docs/DeveloperGuide.md#model-component)
+Role: Developer
+Responsibilities: UI, Testing and Integeration
+* Features implemented:
+ * [Dynamic Calender](images/Ui.png) :Show all the tasks on the calender accroding to their ending timing
+ * Change Calender Date
+ * complete tag coloring
+* Other major contributions:
+ * fix some guitests,eg: addCommandTest,deleteCommandTest,listCommandTes,
+ to make the task manager pass travis test
+ * User Interface Styling
- -----
-#### [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)
diff --git a/docs/ContactUs.md b/docs/ContactUs.md
index 847cfcd1f144..090415209159 100644
--- a/docs/ContactUs.md
+++ b/docs/ContactUs.md
@@ -1,8 +1,8 @@
# 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/CS2103JAN2017-T11-B3/main/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)
-* **Email us** : You can also reach us at `damith [at] comp.nus.edu.sg`
+* **Email us** : You can also reach us at `e0147601 [at] u.nus.edu`
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index fb1d3657e685..38a39d9f19db 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,14 +1,14 @@
-# AddressBook Level 4 - Developer Guide
+# TaskList - Developer Guide
-By : `Team SE-EDU` Since: `Jun 2016` Licence: `MIT`
+By : `CS2103JAN2017-T11-B3` Since: `Feb 2017` Licence: `MIT`
---
-1. [Setting Up](#setting-up)
-2. [Design](#design)
-3. [Implementation](#implementation)
-4. [Testing](#testing)
-5. [Dev Ops](#dev-ops)
+1. [Setting Up](#1-setting-up)
+2. [Design](#2-design)
+3. [Implementation](#3-implementation)
+4. [Testing](#4-testing)
+5. [Dev Ops](#5-dev-ops)
* [Appendix A: User Stories](#appendix-a--user-stories)
* [Appendix B: Use Cases](#appendix-b--use-cases)
@@ -51,7 +51,7 @@ By : `Team SE-EDU` Since: `Jun 2016` &nbs
### 1.3. Configuring Checkstyle
1. Click `Project` -> `Properties` -> `Checkstyle` -> `Local Check Configurations` -> `New...`
2. Choose `External Configuration File` under `Type`
-3. Enter an arbitrary configuration name e.g. addressbook
+3. Enter an arbitrary configuration name e.g. tasklist
4. Import checkstyle configuration file found at `config/checkstyle/checkstyle.xml`
5. Click OK once, go to the `Main` tab, use the newly imported check configuration.
6. Tick and select `files from packages`, click `Change...`, and select the `resources` package
@@ -83,15 +83,12 @@ _Figure 2.1.1 : Architecture Diagram_
The **_Architecture Diagram_** given above explains the high-level design of the App.
Given below is a quick overview of each component.
-> Tip: The `.pptx` files used to create diagrams in this document can be found in the [diagrams](diagrams/) folder.
-> To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose `Save as picture`.
-
-`Main` has only one class called [`MainApp`](../src/main/java/seedu/address/MainApp.java). It is responsible for,
+`Main` has only one class called [`MainApp`](../src/main/java/seedu/task/MainApp.java). It is responsible for,
* At app launch: Initializes the components in the correct sequence, and connects them up with each other.
* At shut down: Shuts down the components and invokes cleanup method where necessary.
-[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components.
+[**`Commons`**](common-classes) represents a collection of classes used by multiple other components.
Two of those classes play important roles at the architecture level.
* `EventsCenter` : This class (written using [Google's Event Bus library](https://github.com/google/guava/wiki/EventBusExplained))
@@ -100,35 +97,33 @@ Two of those classes play important roles at the architecture level.
The rest of the App consists of four components.
-* [**`UI`**](#ui-component) : The UI of the App.
-* [**`Logic`**](#logic-component) : The command executor.
-* [**`Model`**](#model-component) : Holds the data of the App in-memory.
-* [**`Storage`**](#storage-component) : Reads data from, and writes data to, the hard disk.
+* [**`UI`**](ui-component) : The UI of the App.
+* [**`Logic`**](logic-component) : The command executor.
+* [**`Model`**](model-component) : Holds the data of the App in-memory.
+* [**`Storage`**](storage-component) : Reads data from, and writes data to, the hard disk.
Each of the four components
* Defines its _API_ in an `interface` with the same name as the Component.
* Exposes its functionality using a `{Component Name}Manager` class.
-For example, the `Logic` component (see the class diagram given below) defines it's API in the `Logic.java`
+For example, the `Logic` component (see the class diagram given in section 2.3) defines it's API in the `Logic.java`
interface and exposes its functionality using the `LogicManager.java` class.
-
-_Figure 2.1.2 : Class Diagram of the Logic Component_
#### Events-Driven nature of the design
The _Sequence Diagram_ below shows how the components interact for the scenario where the user issues the
command `delete 1`.
-
+
_Figure 2.1.3a : Component interactions for `delete 1` command (part 1)_
->Note how the `Model` simply raises a `AddressBookChangedEvent` when the Address Book data are changed,
+>Note how the `Model` simply raises a `TaskListChangedEvent` when the Task List 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
being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
-
+
_Figure 2.1.3b : Component interactions for `delete 1` command (part 2)_
> Note how the event is propagated through the `EventsCenter` to the `Storage` and `UI` without `Model` having
@@ -139,19 +134,19 @@ The sections below give more details of each component.
### 2.2. UI component
-Author: Alice Bee
+Author: Yu Cheng-Liang
_Figure 2.2.1 : Structure of the UI Component_
-**API** : [`Ui.java`](../src/main/java/seedu/address/ui/Ui.java)
+**API** : [`Ui.java`](../src/main/java/seedu/task/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`, `TaskListPanel`,
+`StatusBarFooter`, `CalendarPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class.
The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files
that are in the `src/main/resources/view` folder.
- For example, the layout of the [`MainWindow`](../src/main/java/seedu/address/ui/MainWindow.java) is specified in
+ For example, the layout of the [`MainWindow`](../src/main/java/seedu/task/ui/MainWindow.java) is specified in
[`MainWindow.fxml`](../src/main/resources/view/MainWindow.fxml)
The `UI` component,
@@ -159,60 +154,100 @@ The `UI` component,
* Executes user commands using the `Logic` 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.
+* uses `Singleton` pattern as its design pattern. Since we do not want the user interface to look complex, for each UI object such as
+ commandbox,resultbox,tasklistview and Calender, our UI just has one copy for each of them.
+
+This is the initial draft for the calender
+
+This is the final implementation for the calender
### 2.3. Logic component
-Author: Bernard Choo
+Author: Wu Heyang
_Figure 2.3.1 : Structure of the Logic Component_
-**API** : [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](../src/main/java/seedu/task/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 person) and/or raise events.
-4. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`.
+* `Logic` uses the `Parser` class to parse the user command.
+* This results in a `Command` object which is executed by the `LogicManager`.
+* The command execution can affect the `Model` (e.g. adding a task) and/or raise events.
+* 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.
-
+
_Figure 2.3.1 : Interactions Inside the Logic Component for the `delete 1` Command_
+Author: Jay Kabra
+
+* The logic behind how to edit a specifc instance of a recurring task is as follows:
+ * The `Parser` recognizes the `editthis` command to delete the occurrence of the selected task
+ from the encapsulated list of RecuirringTaskOccurrence objects (refer to the Model section to see the
+ precise architecture of implementing recurring tasks).
+ * A new task is subsequently instantiated (with its own description, priority, etc. parameters) and added
+ to the underlying Task list. Then the edit parameters are applied to this newly instantianted task.
+
+* The logic behind how to delete a specific instance of a recurring task is as follows:
+ * The `Parser` recognizes the `deletethis` command and subsequently removes the entire task from the list.
+ * Subsequently, it intantiates a new Recurring Task using shared logic with editthis and then adds the
+ recurring task back to the list with the specific instance removed. The effect for the user is a deletetion
+ of a particular recurring task instance.
+
### 2.4. Model component
-Author: Cynthia Dharman
+Author: Jay Kabra
_Figure 2.4.1 : Structure of the Model Component_
-**API** : [`Model.java`](../src/main/java/seedu/address/model/Model.java)
+**API** : [`Model.java`](../src/main/java/seedu/task/model/Model.java)
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
+* Stores a `UserPref` object that represents the user's preferences.
+* Stores the Task List 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.
-* does not depend on any of the other three components.
+* Does not depend on any of the other three components.
+* Defines recurring tasks in the following way:
+ * Class `RecurringTaskOccurrence` encapsulates 2 Timing objects (start & end times) and a boolean to indicate if
+ the occurrence is complete.
+ * Class `Task` encapsulates a list of `RecurringTaskOccurrence` objects. In addition, it also encapsulates a
+ `description`, `priority`, `frequency`, and `UniqueTagList` object for the respective task. Each of these fields is
+ constructed as an object in the backend of the application.
+ * This architecture follows the use of the Abstraction Occurrence Pattern by sharing common fields between
+ instances of the same underlying object in a parent class.
+ * If tasks are recurring then their start/end times are populated based on the given frequency parameter which are
+ subsequently utilized to generate the respective Task's `RecurringTaskOccurrence` objects.
+
### 2.5. Storage component
-Author: Darius Foong
+Author: Tyler Rocha
_Figure 2.5.1 : Structure of the Storage Component_
-**API** : [`Storage.java`](../src/main/java/seedu/address/storage/Storage.java)
+**API** : [`Storage.java`](../src/main/java/seedu/task/storage/Storage.java)
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 Task List data in xml format and read it back.
+* can save Task List data from any properly formatted file.
+* can load Task List data from any properly formatted file.
+
+> The storage component is an example of the singleton design principle because there is only one instance of Storage, accessible through the MainApp class.
+
+> The storage component interacts with the logic component during the load and save command. Here, the load or save command attempts to update the save location for internal storage. In the case of a load command, the logic component makes a save requeset to the storage component. The storage component replies with a notice of either success or failure, since sometimes file operations will fail.
+
+> Adding functionality which allows for saving task data in a new location exemplifies the Open Close principle, because its implementation only added new functions to meet this need, instead of changing existing ones. The Open Close principle states that software should be open to extensions but closed to modifications.
### 2.6. Common classes
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Classes used by multiple components are in the `seedu.task.commons` package.
## 3. Implementation
@@ -222,7 +257,7 @@ We are using `java.util.logging` package for logging. The `LogsCenter` class is
and logging destinations.
* The logging level can be controlled using the `logLevel` setting in the configuration file
- (See [Configuration](#configuration))
+ (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.
@@ -237,9 +272,19 @@ and logging destinations.
### 3.2. Configuration
+Author: Tyler Rocha
+
Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file
(default: `config.json`):
+The config.json file contains several attributes:
+* `appTitle` is the name of the application
+* `logLevel` is the default level for the logger
+* `userPrefsFilePath` is the file path to the user preferences file
+* `taskManagerFilePath` is the file path to the task manager save data
+* `taskManagerName` is the name of the task manager application
+
+`taskManagerFilePath` is manipulated automatically when a successful `save` or `load` command is executed. When this occurs, `taskManagerFilePath` is updated to the user-specified file location, and this location becomes the default for future Task Manager sessions.
## 4. Testing
@@ -263,13 +308,13 @@ We have two types of tests:
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`
+ e.g. `seedu.task.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`
+ e.g. `seedu.task.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`
+ e.g. `seedu.task.logic.LogicManagerTest`
#### Headless GUI Testing
Thanks to the [TestFX](https://github.com/TestFX/TestFX) library we use,
@@ -323,7 +368,7 @@ Here are the steps to convert the project documentation files to PDF format.
1. Make sure you have set up GitHub Pages as described in [UsingGithubPages.md](UsingGithubPages.md#setting-up).
1. Using Chrome, go to the [GitHub Pages version](UsingGithubPages.md#viewing-the-project-site) of the
documentation file.
- e.g. For [UserGuide.md](UserGuide.md), the URL will be `https://.github.io/addressbook-level4/docs/UserGuide.html`.
+ e.g. For [UserGuide.md](UserGuide.md), the URL will be `https://.github.io/main/docs/UserGuide.html`.
1. Click on the `Print` option in Chrome's menu.
1. Set the destination to `Save as PDF`, then click `Save` to save a copy of the file in PDF format.
For best results, use the settings indicated in the screenshot below.
@@ -332,7 +377,7 @@ Here are the steps to convert the project documentation files to PDF format.
### 5.6. 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, Task List 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.
@@ -346,27 +391,66 @@ 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
-
-{More to be added}
+`* * *` | user | add a new task | record tasks that need to be done ‘some day’.
+`* * *` | user | view upcoming tasks | see what needs to be done soon.
+`* * *` | user | delete a task | remove tasks that I no longer care to track.
+`* * *` | new user | view more information about a particular command | learn how to use various commands.
+`* * *` | user | add task deadlines | prioritize what is most urgent.
+`* * *` | user | mark a task as completed | view old tasks.
+`* * *` | user | undo last command | revert my last action if I make a mistake.
+`* * *` | user | add task notes | keep relevant information nearby.
+`* * *` | user | confirm a delete action | avoid accidently delete a task.
+`* * *` | user | view tasks by day | view relevant tasks.
+`* * *` | user | add notification timings | see a popup for high priority tasks prior to the deadline.
+`* * *` | user | assign task prioritize | view tasks by importance.
+`* * *` | user | close the application | save CPU resources.
+`* * *` | user | schedule time to work on a task | plan my time.
+`* * *` | user | modify task details | update tasks.
+`* *` | advanced user | use command shortcuts | save time.
+`* *` | user | backup my data | protect against data loss.
+`* *` | user | create subtasks | break up large tasks.
+`* *` | user | choose custom background | have a pleasant viewing experience.
+`* *` | user | hear nice sounds | further enjoy completing tasks.
+`* *` | user | get reminders | know to start doing something.
+`* *` | user | change calendar view between month/week/day | see my schedule for that time frame.
+`* *` | user | add recurring tasks | avoid repetitive task input.
+`* *` | user | estimate task length | know how much effort is required.
+`* *` | user | add collaborators | know who I have to work with.
+`* *` | user | see error messages for invalid commands | know how to fix my mistake.
+`* *` | user | sort tasks by priority | choose most urgent tasks.
+`* *` | new user | see user guide in a sidebar | have it for easy reference.
+`* *` | user | search tasks by keyword | find tasks.
+`* *` | user | see today's tasks on startup | get started immediately.
+`* *` | user | categorize tasks | organize more effectively.
+`* *` | user | have task manager open on bootup | get started immediately.
+`*` | user | view my command history | review my progress.
+`*` | user | enter distraction-free mode | be stopped from opening games or social websites before tasks are completed
## 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 the `TaskList` and the **Actor** is the `user`, unless specified otherwise)
+
+#### Use case: Create task
+
+**MSS**
+
+1. User requests to create a task with a name
+2. Task Manager create the task
+Use case ends.
+
+**Extensions**
+
+2a. The task with the name given by the user already exists
+> Use case ends
-#### Use case: Delete person
+#### Use case: Delete 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 list tasks
+2. Task Manager shows a list of tasks
+3. User requests to delete a specific task in the list
+4. Task Manager deletes the task
Use case ends.
**Extensions**
@@ -377,19 +461,145 @@ Use case ends.
3a. The given index is invalid
-> 3a1. AddressBook shows an error message
+> 3a1. Task Manager shows an error message
Use case resumes at step 2
-{More to be added}
+#### Use case: Edit/Update task
+
+**MSS**
+
+1. User searches for a task with a given name
+2. Task Manager shows the task
+3. User requests to update/edit the task
+4. Task Manager changes the content of the task
+Use case ends.
+
+**Extensions**
+
+2a. The task does not exist
+
+> Use case ends
+
+4a. The given index is invalid
+
+> 4a1. TaskList shows an error message
+ Use case resumes at step 3
+
+#### Use case: Read task
+
+**MSS**
+
+1. User requests to search for a task with a given name
+2. Task Manager shows the task
+Use case ends.
+
+**Extensions**
+
+2a. The task does not exist
+
+> Use case ends
+
+#### Use case: Complete a task
+
+**MSS**
+
+1. User requests to search for a task with a given name
+2. Task Manager shows the task
+3. User type in the index of the task he/she wants to mark as complete
+4. Task Manager marks the task as completed
+Use case ends.
+
+**Extensions**
+
+2a. The task does not exist
+
+> Use case ends
+
+3a. The given index is invalid
+
+> 3a1. Task Manager shows an error message
+ Use case resumes at step 3
+
+#### Use case: List all task
+
+**MSS**
+
+1. User requests to list all tasks
+2. Task Manager shows all the tasks
+Use case ends.
+
+#### Use case: List a task
+
+**MSS**
+
+1. User type in the index of the task
+2. Task Manager shows the content of the task
+Use case ends.
+
+**Extensions**
+
+2a. The task does not exist
+> 2a1. Task Manager shows an error message
+> Use case resumes at step 1
+
+#### Use case: Save tasks to file
+
+**MSS**
+
+1. User types file location
+2. Task Manager saves tasks in specified save file
+Use case ends.
+
+**Extensions**
+
+2a. The file path does not exist
+> 2a1. Task Manager shows an error message
+> Use case ends.
+
+2b. The file path does not end with a file name
+> 2b1. Task Manager shows an error message
+> Use case ends.
+
+#### Use case: Load tasks from file
+
+**MSS**
+
+1. User types file location
+2. Task Manager loads task data from load file
+Use case ends.
+
+**Extensions**
+
+2a. The file does not exist
+> 2a1. Task Manager shows an error message
+> Use case ends.
+
+2b. The file path does not end with a file name
+> 2b1. Task Manager shows an error message
+> Use case ends.
+
+3c. The load file has an invalid format.
+> 3c1. Task Manager shows an error message
+> Use case ends.
+
## 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 without a noticeable sluggishness in performance for typical usage.
+2. Should be able to hold up to 100 tasks without a noticeable sluggishness in performance for typical usage.
3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands)
should be able to accomplish most of the tasks faster using commands than using the mouse.
-
-{More to be added}
+4. Should be open source.
+5. Should open the app in less than 5 sec.
+6. If the input data's format changes, the developers should be able to make needed adjustments in <20 hours.
+7. A user can install and operate the program without assistance of any kind (except consulting the User Guide Documentation).
+8. To extend the software, proper security measures can be put into place in <100 hours.
+9. Aesthetics of the calendar GUI should be sleek and appealing to 90% of users.
+10. Should be scalable so that a user can change the layout of the GUI based on personal preference.
+11. CPU usage should not exceed 10%.
+12. Support tasks that recur after a specified number of years for 4 years.
+13. Support tasks that recur after a specified number of months for 12 months (1 year).
+14. Support tasks that recur after a specified number of days for 60 days (2 months).
## Appendix D : Glossary
@@ -403,17 +613,64 @@ Use case ends.
## Appendix E : Product Survey
-**Product Name**
+**Google Calendar**
+
+Author: Jay Kabra
+
+Pros:
+* Syncs with your phone so that the calendar is viewable from gmail on your laptop as well as on your phone
+* Allows you to add reminder notifications for events at a customized amount of time
+* Can customize tasks by color
+* Can easily perform CRUD operations on events
+* Can add recurring events and edit them individually if there are exceptions for a particular day
+* More GUI based rather than command line
+* Relatively intuitive for new users
+
+Cons:
+* No way to prioritize tasks
+* Need connection to the internet to view on laptop - not a desktop application
+* Since it is more GUI based, takes more clicks to add a task rather than typing the task in a command line and having the task added
+* appropriately
+
+**Google Tasks**
-Author: ...
+Author: Yu Cheng-Liang
Pros:
+* easy to use
+* have all the basic functions a normal user would use.
+* easy to install
-* ...
-* ...
+Cons:
+* cannot change the color of tasks based on priority
+* alert would not pop out automatically
+* everytime I boot up my computer, I have to open the app manually
+
+**Wunderlist**
+
+Author: Tyler Rocha
+
+Pros:
+* Allows collaboration with friends and family
+* Supports due dates and reminders
+* Accessible from phone, tablet and laptop
Cons:
+* Free account has limited options
+* Needs to be downloaded
+* Paying for more features is expensive
+
+**Hitask**
+
+Author: Wu Heyang
-* ...
-* ...
+Pros:
+* Focus on team collaboration
+* Clean user interface
+* Calendar syncs with Google
+
+Cons:
+* Free trial only
+* Premium is expensive and a monthly expense
+* Lots of features can be overwhelming
diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md
deleted file mode 100644
index d09422a9cd0d..000000000000
--- a/docs/LearningOutcomes.md
+++ /dev/null
@@ -1,320 +0,0 @@
-# Learning Outcomes
-After studying this code and completing the corresponding exercises, you should be able to,
-
-1. [Use High-Level Designs `[LO-HighLevelDesign]`](#use-high-level-designs-lo-highleveldesign)
-1. [Use Event-Driven Programming `[LO-EventDriven]`](#use-event-driven-programming-lo-eventdriven`)
-1. [Use API Design `[LO-ApiDesign]`](#use-api-design-lo-apidesign)
-1. [Use Assertions `[LO-Assertions]`](#use-assertions-lo-assertions)
-1. [Use Logging `[LO-Logging]`](#use-logging-lo-logging)
-1. [Use Defensive Coding `[LO-DefensiveCoding]`](#use-defensive-coding-lo-defensivecoding)
-1. [Use Build Automation `[LO-BuildAutomation]`](#use-build-automation-lo-buildautomation)
-1. [Use Continuous Integration `[LO-ContinuousIntegration]`](#use-continuous-integration-lo-continuousintegration)
-1. [Use Code Coverage `[LO-CodeCoverage]`](#use-code-coverage-lo-codecoverage)
-1. [Apply Test Case Design Heuristics `[LO-TestCaseDesignHeuristics]`](#apply-test-case-design-heuristics-lo-testcasedesignheuristics)
-1. [Write Integration Tests `[LO-IntegrationTests]`](#write-integration-tests-lo-integrationtests)
-1. [Perform System Testing `[LO-SystemTesting]`](#perform-system-testing-lo-systemtesting)
-1. [Automate GUI Testing `[LO-AutomateGuiTesting]`](#automate-gui-testing-lo-automateguitesting)
-1. [Apply Design Patterns `[LO-DesignPatterns]`](#apply-design-patterns-lo-designpatterns)
-1. [Use Static Analysis `[LO-StaticAnalysis]`](#use-static-analysis-lo-staticanalysis)
-1. [Do Code Reviews `[LO-CodeReview]`](#do-code-reviews-lo-codereview)
-
-------------------------------------------------------------------------------------------------------
-
-## Use High-Level Designs `[LO-HighLevelDesign]`
-
-Note how the [Developer Guide](DeveloperGuide.md#architecture) describes the high-level design using an
-_Architecture Diagrams_ and high-level sequence diagrams.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Event-Driven Programming `[LO-EventDriven]`
-
-Note how the [Developer Guide](DeveloperGuide.md#architecture) uses events to communicate with components
-without needing a direct coupling. Also note how the `EventsCenter` class acts as an event dispatcher to
-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
-is given in the [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java)
-
-
-**Resources**
-
-* [A three-minutes video](https://www.youtube.com/watch?v=Un80XoRT1ME) of designing architecture of and
- discovering component APIs for a Game of Tic-Tac-Toe.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Assertions `[LO-Assertions]`
-
-Note how the AddressBook 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
- guide from Oracle.
- * [How to enable assertions in Eclipse](http://stackoverflow.com/questions/5509082/eclipse-enable-assertions)
-
-#### Exercise: Add more assertions
-
- * 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.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Logging `[LO-Logging]`
-
-Note [how the AddressBook app uses Java's `java.util.log` package to do logging](DeveloperGuide.md#31-logging).
-
-**Resources**
-
- * Tutorials
- * [Logging using java.util.logging](http://tutorials.jenkov.com/java-logging/index.html) - a tutorial by Jakob Jenkov
- * [Logging tutorial](http://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html) - a more detailed
- tutorial from Oracle.
- * Logging best practices
- * [Apache Commons Logging guide](http://commons.apache.org/proper/commons-logging/guide.html#Message_PrioritiesLevels)
- * [10 Tips for Proper Application Logging](https://www.javacodegeeks.com/2011/01/10-tips-proper-application-logging.html)
- * [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.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Defensive Coding `[LO-DefensiveCoding]`
-
- Note how AddressBook 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,
-
-* where defensive coding is used
-* where the code can be more defensive
-
-------------------------------------------------------------------------------------------------------
-
-## Use Build Automation `[LO-BuildAutomation]`
-
-Note [how the AddressBook app uses Gradle to automate build tasks](UsingGradle.md).
-
-**Resources**
-
- * Tutorials
- * [Getting started with Gradle (Java)](https://gradle.org/getting-started-gradle-java/) - a tutorial from the Gradle team
- * [Another tutorial](http://www.tutorialspoint.com/gradle/) - from TutorialPoint
-
-#### Exercise: Use gradle to run tasks
-
- * Use gradle to do these tasks (instructions are [here](UsingGradle.md))
- : Run all tests in headless mode, build the jar file.
-
-#### Exercise: Use gradle to manage dependencies
-
- * Note how the build script `build.gradle` file manages third party dependencies such as ControlsFx.
- Update that file to manage a third-party library dependency.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Continuous Integration `[LO-ContinuousIntegration]`
-
-Note [how the AddressBook app uses Travis to perform Continuous Integration](UsingTravis.md).
-([](https://travis-ci.org/se-edu/addressbook-level4))
-
-**Resources**
-
- * Tutorials
- * [Getting started with Travis](https://docs.travis-ci.com/user/getting-started/) - a tutorial from the Travis team
-
-#### Exercise: Use Travis in your own project
-
- * Set up Travis to perform CI on your own project.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Code Coverage `[LO-CodeCoverage]`
-
-Note how our CI server [Travis uses Coveralls to report code coverage](UsingTravis.md).
-([](https://coveralls.io/github/se-edu/addressbook-level4?branch=master))
-After setting up Coveralls for your project, you can visit Coveralls website to find details about the
-coverage of code pushed to your repo. [Here](https://coveralls.io/github/se-edu/addressbook-level4?branch=master) is an example.
-
-
-#### Exercise: Use EclEmma to measure coverage locally
-
- * Install the [EclEmma Eclipse Plugin](http://www.eclemma.org/) in your computer and use that to find code that
- is not covered by the tests. This plugin can help you to find coverage details even before you push code
- to the remote repo.
-
-------------------------------------------------------------------------------------------------------
-
-## Apply Test Case Design Heuristics `[LO-TestCaseDesignHeuristics]`
-
-The [`StringUtilTest.java`](../src/test/java/seedu/address/commons/util/StringUtilTest.java) class gives some examples
-of how to use _Equivalence Partitions_, _Boundary Value Analysis_, and _Test Input Combination Heuristics_ to improve
-the efficiency and effectiveness of test cases testing the
-[`StringUtil.java`](../src/main/java/seedu/address/commons/util/StringUtil.java) class.
-
-
-#### Exercise: Apply Test Case Design Heuristics to other places
-
- * Find answers to these questions:
- * What is an Equivalence Partition? How does it help to improve E&E of testing?
- * What is Boundary Value Analysis? How does it help to improve E&E of testing?
- * What are the heuristics that can be used when combining multiple test inputs?
- * Use the test case design heuristics mentioned above to improve test cases in other places.
-
-------------------------------------------------------------------------------------------------------
-
-## Write Integration Tests `[LO-IntegrationTests]`
-
-Consider the [`StorageManagerTest.java`](../src/test/java/seedu/address/storage/StorageManagerTest.java) class.
-
-* Test methods `prefsReadSave()` and `addressBookReadSave()` are integration tests. Note how they simply test if
- The `StorageManager` class is correctly wired to its dependencies.
-
-* Test method `handleAddressBookChangedEvent_exceptionThrown_eventRaised()` is a unit test because it uses
- _dependency injection_ to isolate the SUT `StorageManger::handleAddressBookChangedEvent(...)` from its
- dependencies.
-
-Compare the above with [`LogicManagerTest`](../src/test/java/seedu/address/logic/LogicManagerTest.java).
-Many of the tests in that class (e.g. `execute_add_*` methods) tests are neither integration nor unit tests.
-They are a _integration + unit_ tests because they not only checks if the LogicManager is correctly wired to its
-dependencies, but also checks the working of its dependencies. For example, the following two lines test the
-the `LogicManager` but also the `Parser`.
-
-```java
-@Test
-public void execute_add_invalidArgsFormat() throws Exception {
- ...
- 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);
- ...
-}
-```
-
-#### Exercise: Write unit and integration tests for the same method.
-
- * Write a unit test for a a high-level methods somewhere in the code base.
- * Write an integration test for the same method.
-
-------------------------------------------------------------------------------------------------------
-
-## Perform System Testing `[LO-SystemTesting]`
-
-Note how tests below `src/test/java/guitests` package
-(e.g [`AddCommandTest.java`](../src/test/java/guitests/AddCommandTest.java)) are system tests because they test
-the entire system end-to-end.
-
-#### Exercise: Write more system tests
-
- * Add some more system tests to the existing system tests.
-
-------------------------------------------------------------------------------------------------------
-
-## Automate GUI Testing `[LO-AutomateGuiTesting]`
-
-Note how this project uses TextFX library to automate GUI testing, including
-[_headless_ GUI testing](DeveloperGuide.md#headless-gui-testing).
-
-#### Exercise: Write more automated GUI tests
- * Add some more automated GUI tests.
-
-------------------------------------------------------------------------------------------------------
-
-## Apply Design Patterns `[LO-DesignPatterns]`
-
-Here are some example design patterns used in the code base.
-
-* **Singleton Pattern** : [`EventsCenter.java`](../src/main/java/seedu/address/commons/core/EventsCenter.java) is
- Singleton class. Its single instance can be accessed using the `EventsCenter.getInsance()` method.
-* **Facade Pattern** : [`StorageManager.java`](../src/main/java/seedu/address/storage/StorageManager.java) is
- not only shielding the internals of the Storage component from outsiders, it is mostly redirecting methods calls
- to its internal components (i.e. minimal logic in the class itself). Therefore, `StorageManager` can be considered a
- Facade class.
-* **Command Pattern** : The [`Command.java`](../src/main/java/seedu/address/logic/commands/Command.java) and its
- sub classes implement the Command Pattern.
-* **Observer Pattern** : The [event driven mechanism](DeveloperGuide.md#events-driven-nature-of-the-design) used by
- this code base employs the Observer pattern.
- For example, objects that are interested in events need to have the `@Subscribe` annotation in the class (this is
- similar to implementing an `<>` interface) and register with the `EventsCenter`. When something noteworthy
- happens, an event is raised and the `EventsCenter` notifies all relevant subscribers. Unlike in the
- Observer pattern in which the `<>` class is notifying all `<>` objects, here the
- `<>` classes simply raises an event and the `EventsCenter` takes care of the notifications.
-* **MVC Pattern** :
- * The 'View' part of the application is mostly in the `.fxml` files in the `src/main/resources/view`
- folder.
- * `Model` component contains the 'Model'.
- * Sub classes of [`UiPart`](../src/main/java/seedu/address/ui/UiPart.java) (e.g. `PersonListPanel` )
- act as 'Controllers', each controlling some part of the UI and communicating with the 'Model' via a `Logic`
- component which sits between the 'Controller' and the 'Model'.
-* **Abstraction Occurrence Pattern** : Not currently used in the app.
-
-
-#### Exercise: Discover other possible applications of the patterns
-
- * Find other possible applications of the patterns to improve the current design.
- e.g. where else in the design can you apply the Singleton pattern?
- * Discuss pros and cons of applying the pattern in each of the situations you found in the previous step.
-
-#### Exercise: Find more applicable patterns
-
- * Learn other _Gang of Four_ Design patterns to see if they are applicable to the app.
-
-------------------------------------------------------------------------------------------------------
-
-## Use Static Analysis `[LO-StaticAnalysis]`
-
- Note how this project uses the [CheckStyle](http://checkstyle.sourceforge.net/) static analysis tool to confirm
- compliance with the coding standard.
-
- Other popular Java static analysis tools:
-
- * [Find Bugs](http://findbugs.sourceforge.net/)
- * [PMD](https://pmd.github.io/)
-
-#### Exercise: Use the CheckStyle Eclipse plugin
-
- * Install the [CheckStyle Eclipse plugin](http://eclipse-cs.sourceforge.net/#!/) and use it to detect
- coding standard violations.
-
-------------------------------------------------------------------------------------------------------
-
-## Do Code Reviews `[LO-CodeReview]`
-
-* Note how some PRs in this project have been reviewed by other developers.
- Here is an [example](https://github.com/se-edu/addressbook-level4/pull/147).
-* Also note how we have used [Codacy](https://www.codacy.com) to do automate some part of the code review workload
- ([](https://www.codacy.com/app/damith/addressbook-level4?utm_source=github.com&utm_medium=referral&utm_content=se-edu/addressbook-level4&utm_campaign=Badge_Grade))
-
-Here are some things you can comment on when reviewing code:
-
-* Read the code from the perspective of a new developer.
- Identify parts that are harder to understand and suggest improvements.
-* Point out any coding standard violations.
-* Suggest better names for methods/variables/classes.
-* Point out unnecessary code duplications.
-* Check if the comments, docs, tests have been updated to match the code change.
-* Check for violation of relevant principles such as the SOLID principles.
-* Point out where SLAP can be improved. e.g. methods that are too long or has too deep nesting.
-* Suggest any other code quality improvements.
-
-**Resources**
-
-* [Code Review Best Practices](https://www.kevinlondon.com/2015/05/05/code-review-best-practices.html) -
- Blog post by Kevin London
-* [Why Code Reviews Matter](https://www.atlassian.com/agile/code-reviews) - An article by Atlassian
-
-#### Exercise: Review a PR
-
-* Review a GitHub PR created by a team member.
-
-
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 03bec764773b..8a963a41fe9a 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,13 +1,14 @@
-# AddressBook Level 4 - User Guide
+# TaskManager - User Guide
-By : `Team SE-EDU` Since: `Jun 2016` Licence: `MIT`
+By : `Team CS2103JAN2017-T11-B3` Since: `Jan 2017` Licence: `MIT`
---
1. [Quick Start](#quick-start)
2. [Features](#features)
-3. [FAQ](#faq)
-4. [Command Summary](#command-summary)
+3. [Notes on Recurring Tasks](#notes-on-recurring-tasks)
+4. [FAQ](#faq)
+5. [Command Summary](#command-summary)
## 1. Quick Start
@@ -16,18 +17,18 @@ By : `Team SE-EDU` Since: `Jun 2016` &nbs
> 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 `TaskManager.jar` from the [releases](../../../releases) tab.
+2. Copy the file to the folder you want to use as the home folder for your task list.
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`** : lists all tasks
+ * **`add`** : add Study for midterm sd/02/03/17 ed/04/03/17 t/study t/midterm :
+ adds the task Study for Midterm, starting from 02/03/17 to 04/03/17 with tags "study" and "midterm" to the task list.
+ * **`delete`**` 3` : deletes the 3rd task shown in the current list
* **`exit`** : exits the app
6. Refer to the [Features](#features) section below for details of each command.
@@ -43,144 +44,371 @@ By : `Team SE-EDU` Since: `Jun 2016` &nbs
### 2.1. Viewing help : `help`
+Opens a side window that displaying all commands and syntax.
Format: `help`
> Help is also shown if you enter an incorrect command e.g. `abcd`
-### 2.2. Adding a person: `add`
+### 2.2. Adding a task: `add`
-Adds a person to the address book
-Format: `add NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...`
+Adds a task to the task list
+Format: `add TASK_NAME [p/PRIORITY_LEVEL] [sd/START_TIMEDATE] [ed/END_TIMEDATE] [t/TAG]...`
-> Persons can have any number of tags (including 0)
+> * The TASK_NAME must be **2 or more characters** long. It can begin with any alphabet, number, or special character.
+> * The PRIORITY_LEVEL must be an integer between **1-3**. 1 is the HIGHEST priority level and 3 is the LOWEST (default) priority level.
+> * **TIMEDATE Format: HH:mm dd/MM/yyyy** (HH:MM is optional). The start/end timing parameters (sd/ed respectively) must be in the date > format specified above. Note that "sd/2:15 1/1/2017 is invalid; the correct format is "sd/02:15 01/01/2017".
+> * To add floating tasks, simply do not specify the START_TIMEDATE and END_TIMEDATE paramters.
+> * To add tasks with deadlines, simply specify the END_TIMEDATE.
+> * To add recurring tasks, see section 2.2.1.
+> * Any of these 3 types of tasks can have 0 or more tags.
+ > * To add a tag, specify it after `t/`. If there are multiple tags, you must use a `t` for each one (see example for more details)
+ > * A single tag cannot be deleted or edited if a task has multiple tags
+> * All fields are optional, except for TASK_NAME
Examples:
-* `add John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01`
-* `add Betsy Crowe t/friend e/betsycrowe@gmail.com a/Newgate Prison p/1234567 t/criminal`
+* `add Watch Friends season 2`
+* `add Submit assignment for MA1101R P/1 sd/09/04/2017 ed/16:00 13/04/2017`
+* `add Study for midterm p/1 ed/04/03/2017 t/study t/midterm`
+* `add Attend CS2103 tutorial p/1 ed/02/03/2017 t/lesson t/school t/tutorial`
-### 2.3. Listing all persons : `list`
+ ### 2.2.1. Adding a recurring task
-Shows a list of all persons in the address book.
-Format: `list`
+ > * Adds a recurring task to the task list
+ > * Format: same as 'add' but specifcy the frequency by r/#_
+ > where '#' is an integer and '_' is either 'd' (day), 'm' (month), or 'y' (year)
+ > * **Note:** Tags are meant to be a commonality for recurring tasks by design; thus they cannot be set differently for a specific instance of a recurring task
-### 2.4. Editing a person : `edit`
+ Examples:
-Edits an existing person in the address book.
-Format: `edit INDEX [NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]...`
+ * `add Attend CS2103 tutorial p/1 sd/11:00 19/01/2017 ed/12:00 19/01/2017 r/7d`
+ * `add Clean fish tank p/2 sd/01/01/2017 ed/03/01/2017 r/2m`
-> * Edits the person at the specified `INDEX`.
- The index refers to the index number shown in the last person listing.
- The index **must be a positive integer** 1, 2, 3, ...
+### 2.3. Listing tasks : `list`
+
+Shows a list of all tasks in the task list.
+Format: `list`
+
+> All tasks will appear in the task list, and tasks will appear in the calendar as well.
+
+Example:
+
+* `list`
+ Shows a list of all tasks in the task list.
+
+ ### 2.3.1 Natural ordering of tasks
+
+ Sorting occurs automatically in Task Manager after every action. First, completed tasks will be sent to the bottom of the list. Then, tasks are sorted by priority, with highest priority tasks at the top of the list. Afterwards, tasks are sorted by their end time, then start time, then alphabetized by description.
+
+### 2.4. Editing a task : `edit`
+
+Edits an existing task in the task list.
+Format: `edit INDEX [TASK_NAME] [p/PRIORITY] [sd/START_TIMEDATE] [ed/END_TIMEDATE] [t/TAG]...`
+Editing a recurring task in this way will edit all instances
+
+> * The TASK_NAME must be **2 or more characters** long. It can begin with any alphabet, number, or special character.
+> * The PRIORITY_LEVEL must be an integer between **1-3**. 1 is the HIGHEST priority level and 3 is the LOWEST (default) priority level.
+> * **TIMEDATE Format: HH:mm dd/MM/yyyy** (HH:MM is optional). The start/end timing parameters (sd/ed respectively) must be in the date > format specified above. Note that "sd/2:15 1/1/2017 is invalid; the correct format is "sd/02:15 01/01/2017".
+> * Edits the task at the specified `INDEX`.
+> The index refers to the index number shown in the last task listing.
+> The index **must be a positive integer** 1, 2, 3, etc.
> * At least one of the optional fields must be provided.
> * Existing values will be updated to the input values.
-> * When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-> * You can remove all the person's tags by typing `t/` without specifying any tags after it.
+> * When editing tags, the existing tags of the task will be removed i.e adding of tags is not cumulative.
+> * You can remove all the task's tags by typing `t/` without specifying any tags after it.
+> * If you want to clear the START_TIMEDATE or END_TIMEDATE of a task, use `sd/floating` and `ed/floating` respectively
+> in the edit command (see example below).
+> * You can edit the frequency of a recurring task following the same syntax. Note that all occurrences will be changed
+> according to the frequency specified.
+> * Once a non-recurring task is created, it cannot be `edit`ed and made into a recurring task. You must create a new task using
+> * `add` and specifiy a frequency with `r/` if you want to make a non-recurring task into a recurring one.
Examples:
-* `edit 1 p/91234567 e/johndoe@yahoo.com`
- Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@yahoo.com` respectively.
+* `edit 1 sd/03/03/17`
+ Edits the start date of task 1 to 03/03/17.
+
+* `edit 2 Do Algorithm Assignment t/`
+ Edits the name of the 2nd task to be `Do Algorithm Assignment` and clears all existing tags.
+
+* `edit 4 ed/floating p/1`
+ Removes the end timing for task 4 and updates its priority to 1.
+
+* `edit 1 r/1y`
+ Edits the frequency of task 1 (assuming it is a recurring task) and changes it to 1 year.
+
+ ### 2.4.1. Editing a specific instance of a recurring task : `editthis`
+
+ Format: `editthis INDEX [NAME] p/PRIORITY sd/START_TIMEDATE ed/END_TIMEDATE...`
+
+ > * Edits a specific instance of a recurring task
+ > * After editing this instance, the edited task will no longer be a part of the recurring sequence
+
+ Examples:
+
+ * `edithis 2 sd/01/01/2017`
+ Edits the start date of task 2 (which is recurring)
-* `edit 2 Betsy Crower t/`
- Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+ * `edithis 2 Go to 2103 Lecture`
+ Edits the description of task 2 (which is recurring)
-### 2.5. Finding all persons containing any keyword in their name: `find`
+### 2.5. Finding all tasks containing any keyword: `find`
-Finds persons whose names contain any of the given keywords.
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Finds tasks whose TASK_NAME, PRIORITY, START_TIMEDATE, or END_TIMEDATE contain any of the given keywords.
+Format 1: `find 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. e.g `assignment` will match `AssIGNmEnt`
+> * The order of the keywords does not matter. e.g. `do assignment to` will match `assignment to do`
+> * Only full words will be matched e.g. `assign` will not match `assignment`
+> * Task matching at least one keyword will be returned (i.e. `OR` search) e.g. `assignment` will match `do algorithm assignment`
+> * Note: `find` does not search on a task's tags
Examples:
-* `find John`
- Returns `John Doe` but not `john`
-* `find Betsy Tim John`
- Returns Any person having names `Betsy`, `Tim`, or `John`
+* `find midterm`
+ Returns `Study for midterm`
-### 2.6. Deleting a person : `delete`
+ * `find 11/01/2017`
+ Returns all tasks with start or end timings on January 11, 2017.
-Deletes the specified person from the address book. Irreversible.
+ * `find 1`
+ Returns tasks with a priority of 1 (i.e. a HIGH priority).
+
+### 2.5.1. Finding an instance of a recurring task
+ > * Execute 'find' with the same syntax as above
+ > * However, only one instance will show up in the list after executing 'list'
+ > * The instance in 'list' will be updated to match the parameters after executing a valid 'find'
+
+ Examples:
+
+ * `add feed cat sd/10/05/2017 ed/10/05/2017 r/1d`
+ The task is displayed in the list with the above parameters
+ * `find 11/05/2017`
+ Returns `feed cat sd/11/05/2017 ed/11/05/2017`
+ * `list`
+ Returns all of the tasks with 'feed cat's' instance with START_TIMEDATE: 11/05/2017 and END_TIMEDATE: 11/05/2017
+
+### 2.6. Deleting a task : `delete`
+
+Deletes the specified task from the task list.
Format: `delete INDEX`
-> Deletes the person 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, ...
+> * Deletes the task 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, ...
Examples:
* `list`
`delete 2`
- Deletes the 2nd person in the address book.
-* `find Betsy`
+ Deletes the 2nd task in the task list.
+
+* `find tutorial`
`delete 1`
- Deletes the 1st person in the results of the `find` command.
+ Deletes the 1st task in the results of the `find` command.
+
+ ### 2.6.1. Deleting a specific instance of a recurring task : `deletethis`
+
+ Deletes the specific occurrence of the recurring task from the list
+ Format: `deletethis INDEX`
+
+ > * Deletes the specific occurrence of a recurring task 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, ...
+ > * Upon deleting an instance, the task list will be updated with the next recent occurrence.
+ If there is no more occurrences, then the entire recurring task will be removed from the list.
+ > * **Note:** Calling `deletethis` on a non-recurring task is supported - functionality is equivalent to
+ calling `delete` on the same task.
-### 2.7. Select a person : `select`
+ Example:
-Selects the person identified by the index number used in the last person listing.
-Format: `select INDEX`
+* `find 05/01/2017`
+ `deletethis 1`
+ Executes a search to find tasks on January 5th the deletes the 1st task (which is a recurring instance).
-> Selects the person and loads the Google search page the person 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, ...
+### 2.7. Complete a task : `complete`
+
+Marks the specified task as `Completed`. The task is automatically added with a `complete` tag.
+Format: `complete INDEX`
+
+> * Mark the task at the specified `INDEX` as `Completed`.
+> * The index refers to the index number shown in the most recent listing.
+> * The index **must be a positive integer** 1, 2, 3, ...
+> * To complete a specific instance of a recurring task, follow the same syntax.
+> * **Note:** `complete` ALL instances of a recurring task is not a practical application of this command and thus is not supported.
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.
+ `complete 2`
+ Completes the 2nd task in the task list.
+* `find tutorial`
+ `complete 1`
+ Completes the 1st task in the results of the `find` command.
+
+### 2.8. Allocate priority to a task: `prioritize`
+
+Puts a priority level to a task.
+Format: `prioritize INDEX PRIORITY_LEVEL`
-### 2.8. Clearing all entries : `clear`
+> * Allocates a priority leve of `PRIORITY_LEVEL` to the task at the specified `INDEX`.
+> * The index **must be a positive interger** 1, 2, 3,...
+> * The priority level **must be a positive integer from 1 to 3**, 1 being the highest priority and 3 being the least.
+> * Using `prioritize` on a recurring task will change the priority of ALL occurrences.
+> * **Note:** To prioritize a specific instance of a recrring task, use `editthis INDEX p/#` where '#' represents the edited
+> priority.
+
+Examples:
+
+* `list`
+ `prioritize 2 3`
+ Puts a priority level of 3 to the 2nd task in the task list. If the 2nd task is recurring, then all occurrences will have priority 3.
-Clears all entries from the address book.
+* `find attend 2103 lecture`
+`editthis 1 p/1`
+Puts a priority level of 1 to the 1st task in the resulting list (assuming it is recurring, only this occurrence will have priority 1).
+
+### 2.9. Clearing all entries : `clear`
+
+Clears all entries from the task list.
Format: `clear`
-### 2.9. Exiting the program : `exit`
+### 2.10. Exiting the program : `exit`
Exits the program.
Format: `exit`
-### 2.10. Saving the data
+Example:
+
+* `exit`
+The application will shut down.
+
+### 2.11. Saving the data : `save`
+
+Saves task manager data in specified file location.
+Format: `save PATH/TO/SAVE_LOCATION`
+
+* Task list data is saved in the hard disk automatically after any command that changes the data.
+* As a result, there is no need to save manually.
+* The exception is when you want to save data to a new location.
+
+Examples:
+
+* `save` task_manager_back_up.xml
+* `save` data/taskmanager.xml
+
+### 2.12. Loading the data : `load`
+
+Loads task manager data from specified file location
+Format: `load PATH/TO/LOAD_LOCATION`
+
+* Loading occurs automatically when Task Manager opens.
+* As a result, the load command is only necessary when Task data should be loaded from a new location.
+
+Examples:
+
+* `load` task_manager_old.xml
+* `load` data/saved_task_manager.xml
+
+### 2.13. Revert the previous change : `undo`
+
+Undo the previous change made to the task manager.
+Format: `undo`
+> * The undo command is able to undo all changes made after the application is opened.
+> * When there is nothing to undo, an error message will be shown.
+> * **Note:** `undo` only works in the same session (i.e. `exit`ing the application, then restarting it, and
+> then calling `undo` will not restore changes made in the past session)
-Address book data are saved in the hard disk automatically after any command that changes the data.
-There is no need to save manually.
+Examples:
+
+* `undo`
+
+### 2.14. Revert the previous undo change: `redo`
+
+Revert the previous undo change to the task manager.
+Format: `redo`
+> * The redo command is able to redo multiple undos.
+> * If you call `undo`, make some changes, then call `redo`, the effect is no change since there is nothing to `redo`.
+> Essentially, `redo` must be called directly after an `undo`, else the logic does not make sense.
+
+Examples:
+
+* `undo`, `redo`
+Redo's the command which was just undone
+*`delete 1`, `undo`, `add floating task`, `redo`
+No change (nothing to `redo`)
+
+## 3. Notes on Recurring Tasks
+
+Recurring tasks are those that are meant to repeat after a specified amount of time. This application supports
+the implementation of such tasks. A few things to note about how to use this feature:
-## 3. FAQ
+* The START/END TIMEDATE should be specified for one occurrence. A common misconception is specifiying these paramters
+ as the start and end timings of when the overall recurring pattern should start/end respectively.
+* So for example, if the recurring task you want to add is "Attend 2103 Tutorial" which begins on January 19, 2017 and occurs
+ every week from 11am - 12pm, the syntax of the respective command would be as follows:
+ `add Attend 2103 Tutorial sd/11:00 19/01/2017 ed/12:00 19/01/2017 r/7d`.
+* The task would then automatically be generated for the next 60 days (refer to non-functional requirements).
+* If this task ends before 60 days, then you can execute `delete INDEX` where INDEX specifies the index of the recurring task on
+ the User Interface. This will remove all occurrences of the recursive task from the Task Manager.
+* If this task runs longer then 60 days, then you will have to re-add the task following the same syntax for `add` so that it
+ recurrs for another 60 days.
+* Both the START_TIMEDATE and the END_TIMEDATE parameters must be specified for initiating a recurring task.
+
+## 4. 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.
+**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 task list folder.
+**Q**: How do I change the calendar to view a different month?
+**A**: Enter a date in the text field and click enter. The calendar will be updated with the new view.
+**Q**: How do I undo changes made in a previous session?
+**A**: Command history is cleared upon exiting Task Manager. Thus, does changes cannot be undone.
-## 4. Command Summary
+## 5. Command Summary
-* **Add** `add NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...`
- e.g. `add James Ho p/22224444 e/jamesho@gmail.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
+* **Add** `add TASK_NAME p/1 sd/START_TIMEDATE ed/END_TIMEDATE [t/TAG]...`
+ e.g. `add Study for midterm p/1 sd/04/03/2017 ed/04/04/2017 t/study t/midterm`
* **Clear** : `clear`
* **Delete** : `delete INDEX`
e.g. `delete 3`
+* **Deletethis** : `deletethis INDEX`
+ e.g. `deletethis 3`
+
+* **Edit** : `edit INDEX`
+ e.g. `edit 1 ed/03/03/2017`
+
+* **Editthis** : `editthis INDEX`
+ e.g. `editthis 1 ed/03/03/2017`
+
* **Find** : `find KEYWORD [MORE_KEYWORDS]`
- e.g. `find James Jake`
+ e.g. `find assignment`
+ `find tutorial`
* **List** : `list`
- e.g.
+ e.g. `list`
* **Help** : `help`
- e.g.
-* **Select** : `select INDEX`
- e.g.`select 2`
+* **Complete** : `complete INDEX`
+ e.g. `complete 2`
+
+* **Prioritze** : `prioritize INDEX PRIORITY_LEVEL`
+ e.g. `priority 2 3`
+
+* **Exit** : `exit`
+ e.g. `exit`
+
+* **Load** : `load PATH/TO/LOAD_FILE`
+ e.g. `load /Documents/task/tasklist.xml`
+
+* **Save** : `save PATH/TO/SAVE_FILE`
+ e.g. `save /Documents/task/tasklist.xml`
+* **Redo** : `redo`
+ e.g. `redo`
+* **Undo** : `undo`
+ e.g. `undo`
diff --git a/docs/UsingGradle.md b/docs/UsingGradle.md
index 3c66f0301042..b9c3585a2d5d 100644
--- a/docs/UsingGradle.md
+++ b/docs/UsingGradle.md
@@ -75,7 +75,7 @@ To enable _exceptions_ to code styles, add in the comment `//CODESTYLE.OFF: Rule
Runs all tests in the `guitests` package
* **`nonGuiTests`**
- Runs all non-GUI tests in the `seedu.address` package
+ Runs all non-GUI tests in the `seedu.task` package
* **`headless`**
Sets the test mode as _headless_.
diff --git a/docs/diagrams/HighLevelSequenceDiagrams.pptx b/docs/diagrams/HighLevelSequenceDiagrams.pptx
index 38332090a79a..479439206768 100644
Binary files a/docs/diagrams/HighLevelSequenceDiagrams.pptx and b/docs/diagrams/HighLevelSequenceDiagrams.pptx differ
diff --git a/docs/diagrams/LogicComponentClassDiagram.pptx b/docs/diagrams/LogicComponentClassDiagram.pptx
index 1e20c6a3a3d6..e1384118bfc7 100644
Binary files a/docs/diagrams/LogicComponentClassDiagram.pptx and b/docs/diagrams/LogicComponentClassDiagram.pptx differ
diff --git a/docs/diagrams/LogicComponentSequenceDiagram.pptx b/docs/diagrams/LogicComponentSequenceDiagram.pptx
index e0269a4eb151..033ad498fa00 100644
Binary files a/docs/diagrams/LogicComponentSequenceDiagram.pptx and b/docs/diagrams/LogicComponentSequenceDiagram.pptx differ
diff --git a/docs/images/Architecture.png b/docs/images/Architecture.png
index bdc789000f77..2b55ec449522 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
deleted file mode 100644
index 3c65e2eb9172..000000000000
Binary files a/docs/images/DeletePersonSdForLogic.png and /dev/null differ
diff --git a/docs/images/DeleteTaskSdForLogic.png b/docs/images/DeleteTaskSdForLogic.png
new file mode 100644
index 000000000000..c17512047f72
Binary files /dev/null and b/docs/images/DeleteTaskSdForLogic.png 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/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index 1f95b833a4d1..1185b6965844 100644
Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png 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 96e7c7975ff2..c571e20a8a4f 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/SDforDeletePerson.png b/docs/images/SDforDeletePerson.png
deleted file mode 100644
index 1e836f10dcd8..000000000000
Binary files a/docs/images/SDforDeletePerson.png and /dev/null differ
diff --git a/docs/images/SDforDeletePersonEventHandling.png b/docs/images/SDforDeletePersonEventHandling.png
deleted file mode 100644
index ecec0805d32c..000000000000
Binary files a/docs/images/SDforDeletePersonEventHandling.png and /dev/null differ
diff --git a/docs/images/SDforDeleteTask.png b/docs/images/SDforDeleteTask.png
new file mode 100644
index 000000000000..a2af3e857a97
Binary files /dev/null and b/docs/images/SDforDeleteTask.png differ
diff --git a/docs/images/SDforDeleteTaskEventHandling.png b/docs/images/SDforDeleteTaskEventHandling.png
new file mode 100644
index 000000000000..9e6c9de81c57
Binary files /dev/null and b/docs/images/SDforDeleteTaskEventHandling.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 7a4cd2700cbf..2fb0364fda45 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 7121a50a442a..a24f6b380237 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 369469ef176e..f1586ac21c55 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/UiDraft.png b/docs/images/UiDraft.png
new file mode 100644
index 000000000000..912dde415c05
Binary files /dev/null and b/docs/images/UiDraft.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/docs/images/chengliang.jpg b/docs/images/chengliang.jpg
new file mode 100644
index 000000000000..2e51ba959498
Binary files /dev/null and b/docs/images/chengliang.jpg differ
diff --git a/docs/images/jay500s.PNG b/docs/images/jay500s.PNG
new file mode 100644
index 000000000000..b19667be676d
Binary files /dev/null and b/docs/images/jay500s.PNG differ
diff --git a/docs/images/tylerrocha.jpg b/docs/images/tylerrocha.jpg
new file mode 100644
index 000000000000..fddb71445305
Binary files /dev/null and b/docs/images/tylerrocha.jpg differ
diff --git a/docs/images/whycaiji.jpg b/docs/images/whycaiji.jpg
new file mode 100644
index 000000000000..8cfa88501005
Binary files /dev/null and b/docs/images/whycaiji.jpg differ
diff --git a/secret_folder/secret_tasks b/secret_folder/secret_tasks
new file mode 100644
index 000000000000..93f65208e5e4
--- /dev/null
+++ b/secret_folder/secret_tasks
@@ -0,0 +1,24 @@
+
+
+
+ Say so long to Fiona Kunz
+ 1
+ false
+ 0
+ owesMoney
+ friends
+
+ false
+
+ 02/03/2100
+ 2100-03-02T00:00:00+08:00
+
+
+ 01/02/2017
+ 2017-02-01T00:00:00+08:00
+
+
+
+ owesMoney
+ friends
+
diff --git a/secret_folder/secret_tasks.xml b/secret_folder/secret_tasks.xml
new file mode 100644
index 000000000000..93f65208e5e4
--- /dev/null
+++ b/secret_folder/secret_tasks.xml
@@ -0,0 +1,24 @@
+
+
+
+ Say so long to Fiona Kunz
+ 1
+ false
+ 0
+ owesMoney
+ friends
+
+ false
+
+ 02/03/2100
+ 2100-03-02T00:00:00+08:00
+
+
+ 01/02/2017
+ 2017-02-01T00:00:00+08:00
+
+
+
+ owesMoney
+ friends
+
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 7db9b5c48ed6..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/PersonPanelSelectionChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java
deleted file mode 100644
index 76e08f587e02..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/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
deleted file mode 100644
index 0926c969460a..000000000000
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package seedu.address.logic;
-
-import java.util.logging.Logger;
-
-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.commands.exceptions.CommandException;
-import seedu.address.logic.parser.Parser;
-import seedu.address.model.Model;
-import seedu.address.model.person.ReadOnlyPerson;
-import seedu.address.storage.Storage;
-
-/**
- * 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) throws CommandException {
- 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 8c79d17d6b4e..000000000000
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package seedu.address.logic.commands;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.person.UniquePersonList;
-import seedu.address.model.tag.Tag;
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * 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;
-
- /**
- * Creates an AddCommand 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() throws CommandException {
- assert model != null;
- try {
- model.addPerson(toAdd);
- return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
- } catch (UniquePersonList.DuplicatePersonException e) {
- throw new CommandException(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 98747521eb80..000000000000
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ /dev/null
@@ -1,20 +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!";
-
-
- @Override
- public CommandResult execute() {
- assert model != null;
- model.resetData(new AddressBook());
- 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 47e0a0b09641..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.logic.commands.exceptions.CommandException;
-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() throws CommandException {
-
- UnmodifiableObservableList lastShownList = model.getFilteredPersonList();
-
- if (lastShownList.size() < targetIndex) {
- throw new CommandException(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/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
deleted file mode 100644
index 38f8a6c678c9..000000000000
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package seedu.address.logic.commands;
-
-import java.util.List;
-import java.util.Optional;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.util.CollectionUtil;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.person.ReadOnlyPerson;
-import seedu.address.model.person.UniquePersonList;
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * Edits the details of an existing person in the address book.
- */
-public class EditCommand extends Command {
-
- public static final String COMMAND_WORD = "edit";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the last person listing. "
- + "Existing values will be overwritten by the input values.\n"
- + "Parameters: INDEX (must be a positive integer) [NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS ] [t/TAG]...\n"
- + "Example: " + COMMAND_WORD + " 1 p/91234567 e/johndoe@yahoo.com";
-
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
- public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
-
- private final int filteredPersonListIndex;
- private final EditPersonDescriptor editPersonDescriptor;
-
- /**
- * @param filteredPersonListIndex the index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
- */
- public EditCommand(int filteredPersonListIndex, EditPersonDescriptor editPersonDescriptor) {
- assert filteredPersonListIndex > 0;
- assert editPersonDescriptor != null;
-
- // converts filteredPersonListIndex from one-based to zero-based.
- this.filteredPersonListIndex = filteredPersonListIndex - 1;
-
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
- }
-
- @Override
- public CommandResult execute() throws CommandException {
- List lastShownList = model.getFilteredPersonList();
-
- if (filteredPersonListIndex >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- ReadOnlyPerson personToEdit = lastShownList.get(filteredPersonListIndex);
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
-
- try {
- model.updatePerson(filteredPersonListIndex, editedPerson);
- } catch (UniquePersonList.DuplicatePersonException dpe) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
- model.updateFilteredListToShowAll();
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, personToEdit));
- }
-
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(ReadOnlyPerson personToEdit,
- EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- Name updatedName = editPersonDescriptor.getName().orElseGet(personToEdit::getName);
- Phone updatedPhone = editPersonDescriptor.getPhone().orElseGet(personToEdit::getPhone);
- Email updatedEmail = editPersonDescriptor.getEmail().orElseGet(personToEdit::getEmail);
- Address updatedAddress = editPersonDescriptor.getAddress().orElseGet(personToEdit::getAddress);
- UniqueTagList updatedTags = editPersonDescriptor.getTags().orElseGet(personToEdit::getTags);
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
- }
-
- /**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
- */
- public static class EditPersonDescriptor {
- private Optional name = Optional.empty();
- private Optional phone = Optional.empty();
- private Optional email = Optional.empty();
- private Optional address = Optional.empty();
- private Optional tags = Optional.empty();
-
- public EditPersonDescriptor() {}
-
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- this.name = toCopy.getName();
- this.phone = toCopy.getPhone();
- this.email = toCopy.getEmail();
- this.address = toCopy.getAddress();
- this.tags = toCopy.getTags();
- }
-
- /**
- * Returns true if at least one field is edited.
- */
- public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyPresent(this.name, this.phone, this.email, this.address, this.tags);
- }
-
- public void setName(Optional name) {
- assert name != null;
- this.name = name;
- }
-
- public Optional getName() {
- return name;
- }
-
- public void setPhone(Optional phone) {
- assert phone != null;
- this.phone = phone;
- }
-
- public Optional getPhone() {
- return phone;
- }
-
- public void setEmail(Optional email) {
- assert email != null;
- this.email = email;
- }
-
- public Optional getEmail() {
- return email;
- }
-
- public void setAddress(Optional address) {
- assert address != null;
- this.address = address;
- }
-
- public Optional getAddress() {
- return address;
- }
-
- public void setTags(Optional tags) {
- assert tags != null;
- this.tags = tags;
- }
-
- public Optional getTags() {
- return tags;
- }
- }
-}
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 e7bffd41eac7..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.core.UnmodifiableObservableList;
-import seedu.address.commons.events.ui.JumpToListRequestEvent;
-import seedu.address.logic.commands.exceptions.CommandException;
-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() throws CommandException {
-
- UnmodifiableObservableList lastShownList = model.getFilteredPersonList();
-
- if (lastShownList.size() < targetIndex) {
- throw new CommandException(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/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
deleted file mode 100644
index 24e335e43910..000000000000
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.NoSuchElementException;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.IncorrectCommand;
-
-/**
- * Parses input arguments and creates a new AddCommand object
- */
-public class AddCommandParser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the AddCommand
- * and returns an AddCommand object for execution.
- */
- public Command parse(String args) {
- ArgumentTokenizer argsTokenizer =
- new ArgumentTokenizer(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
- argsTokenizer.tokenize(args);
- try {
- return new AddCommand(
- argsTokenizer.getPreamble().get(),
- argsTokenizer.getValue(PREFIX_PHONE).get(),
- argsTokenizer.getValue(PREFIX_EMAIL).get(),
- argsTokenizer.getValue(PREFIX_ADDRESS).get(),
- ParserUtil.toSet(argsTokenizer.getAllValues(PREFIX_TAG))
- );
- } catch (NoSuchElementException nsee) {
- return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- } catch (IllegalValueException ive) {
- return new IncorrectCommand(ive.getMessage());
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
deleted file mode 100644
index 135b6ade524b..000000000000
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.logic.commands.IncorrectCommand;
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * Parses input arguments and creates a new EditCommand object
- */
-public class EditCommandParser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the EditCommand
- * and returns an EditCommand object for execution.
- */
- public Command parse(String args) {
- assert args != null;
- ArgumentTokenizer argsTokenizer =
- new ArgumentTokenizer(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
- argsTokenizer.tokenize(args);
- List> preambleFields = ParserUtil.splitPreamble(argsTokenizer.getPreamble().orElse(""), 2);
-
- Optional index = preambleFields.get(0).flatMap(ParserUtil::parseIndex);
- if (!index.isPresent()) {
- return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE));
- }
-
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- try {
- editPersonDescriptor.setName(ParserUtil.parseName(preambleFields.get(1)));
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argsTokenizer.getValue(PREFIX_PHONE)));
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argsTokenizer.getValue(PREFIX_EMAIL)));
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argsTokenizer.getValue(PREFIX_ADDRESS)));
- editPersonDescriptor.setTags(parseTagsForEdit(ParserUtil.toSet(argsTokenizer.getAllValues(PREFIX_TAG))));
- } catch (IllegalValueException ive) {
- return new IncorrectCommand(ive.getMessage());
- }
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- return new IncorrectCommand(EditCommand.MESSAGE_NOT_EDITED);
- }
-
- return new EditCommand(index.get(), editPersonDescriptor);
- }
-
- /**
- * Parses {@code Collection tags} into an {@code Optional} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Optional} containing zero tags.
- */
- private Optional parseTagsForEdit(Collection tags) throws IllegalValueException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
- }
-
-}
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 e4d2e8c036e5..000000000000
--- a/src/main/java/seedu/address/logic/parser/Parser.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.ExitCommand;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.HelpCommand;
-import seedu.address.logic.commands.IncorrectCommand;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.commands.SelectCommand;
-
-/**
- * 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+)(?.*)");
-
- /**
- * 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 new AddCommandParser().parse(arguments);
-
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
-
- case SelectCommand.COMMAND_WORD:
- return new SelectCommandParser().parse(arguments);
-
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
-
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
-
- case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(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);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/SelectCommandParser.java b/src/main/java/seedu/address/logic/parser/SelectCommandParser.java
deleted file mode 100644
index 1023158eb17c..000000000000
--- a/src/main/java/seedu/address/logic/parser/SelectCommandParser.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import java.util.Optional;
-
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.IncorrectCommand;
-import seedu.address.logic.commands.SelectCommand;
-
-/**
- * Parses input arguments and creates a new SelectCommand object
- */
-public class SelectCommandParser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the SelectCommand
- * and returns an SelectCommand object for execution.
- */
- public Command parse(String args) {
- Optional index = ParserUtil.parseIndex(args);
- if (!index.isPresent()) {
- return new IncorrectCommand(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE));
- }
-
- return new SelectCommand(index.get());
- }
-
-}
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 36b98b7aae48..000000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package seedu.address.model;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-import javafx.collections.ObservableList;
-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 seedu.address.model.person.UniquePersonList.DuplicatePersonException;
-import seedu.address.model.tag.Tag;
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * 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;
-
- /*
- * The 'unusual' code block below is an non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- tags = new UniqueTagList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons and Tags in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
-//// list overwrite operations
-
- public void setPersons(List extends ReadOnlyPerson> persons)
- throws UniquePersonList.DuplicatePersonException {
- this.persons.setPersons(persons);
- }
-
- public void setTags(Collection tags) throws UniqueTagList.DuplicateTagException {
- this.tags.setTags(tags);
- }
-
- public void resetData(ReadOnlyAddressBook newData) {
- assert newData != null;
- try {
- setPersons(newData.getPersonList());
- } catch (UniquePersonList.DuplicatePersonException e) {
- assert false : "AddressBooks should not have duplicate persons";
- }
- try {
- setTags(newData.getTagList());
- } catch (UniqueTagList.DuplicateTagException e) {
- assert false : "AddressBooks should not have duplicate tags";
- }
- syncMasterTagListWith(persons);
- }
-
-//// 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 {
- syncMasterTagListWith(p);
- persons.add(p);
- }
-
- /**
- * Updates the person in the list at position {@code index} with {@code editedReadOnlyPerson}.
- * {@code AddressBook}'s tag list will be updated with the tags of {@code editedReadOnlyPerson}.
- * @see #syncMasterTagListWith(Person)
- *
- * @throws DuplicatePersonException if updating the person's details causes the person to be equivalent to
- * another existing person in the list.
- * @throws IndexOutOfBoundsException if {@code index} < 0 or >= the size of the list.
- */
- public void updatePerson(int index, ReadOnlyPerson editedReadOnlyPerson)
- throws UniquePersonList.DuplicatePersonException {
- assert editedReadOnlyPerson != null;
-
- Person editedPerson = new Person(editedReadOnlyPerson);
- syncMasterTagListWith(editedPerson);
- // TODO: the tags master list will be updated even though the below line fails.
- // This can cause the tags master list to have additional tags that are not tagged to any person
- // in the person list.
- persons.updatePerson(index, editedPerson);
- }
-
- /**
- * 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 syncMasterTagListWith(Person person) {
- final UniqueTagList personTags = person.getTags();
- tags.mergeFrom(personTags);
-
- // Create map with values = tag object references in the master list
- // used for checking person tag references
- final Map masterTagObjects = new HashMap<>();
- tags.forEach(tag -> masterTagObjects.put(tag, tag));
-
- // Rebuild the list of person tags to point to the relevant tags in the master tag list.
- final Set correctTagReferences = new HashSet<>();
- personTags.forEach(tag -> correctTagReferences.add(masterTagObjects.get(tag)));
- person.setTags(new UniqueTagList(correctTagReferences));
- }
-
- /**
- * Ensures that every tag in these persons:
- * - exists in the master list {@link #tags}
- * - points to a Tag object in the master list
- * @see #syncMasterTagListWith(Person)
- */
- private void syncMasterTagListWith(UniquePersonList persons) {
- persons.forEach(this::syncMasterTagListWith);
- }
-
- 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.asObservableList().size() + " persons, " + tags.asObservableList().size() + " tags";
- // TODO: refine later
- }
-
- @Override
- public ObservableList getPersonList() {
- return new UnmodifiableObservableList<>(persons.asObservableList());
- }
-
- @Override
- public ObservableList getTagList() {
- return new UnmodifiableObservableList<>(tags.asObservableList());
- }
-
- @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.equalsOrderInsensitive(((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 bb376de44717..000000000000
--- a/src/main/java/seedu/address/model/Model.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package seedu.address.model;
-
-import java.util.Set;
-
-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 seedu.address.model.person.UniquePersonList.DuplicatePersonException;
-
-/**
- * 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;
-
- /**
- * Updates the person located at {@code filteredPersonListIndex} with {@code editedPerson}.
- *
- * @throws DuplicatePersonException if updating the person's details causes the person to be equivalent to
- * another existing person in the list.
- * @throws IndexOutOfBoundsException if {@code filteredPersonListIndex} < 0 or >= the size of the filtered list.
- */
- void updatePerson(int filteredPersonListIndex, ReadOnlyPerson editedPerson)
- 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 cc45d6a849fe..000000000000
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package seedu.address.model;
-
-import java.util.Set;
-import java.util.logging.Logger;
-
-import javafx.collections.transformation.FilteredList;
-import seedu.address.commons.core.ComponentManager;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.core.UnmodifiableObservableList;
-import seedu.address.commons.events.model.AddressBookChangedEvent;
-import seedu.address.commons.util.CollectionUtil;
-import seedu.address.commons.util.StringUtil;
-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;
-
-/**
- * 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 and userPrefs.
- */
- public ModelManager(ReadOnlyAddressBook addressBook, UserPrefs userPrefs) {
- super();
- assert !CollectionUtil.isAnyNull(addressBook, userPrefs);
-
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
-
- this.addressBook = new AddressBook(addressBook);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
- }
-
- public ModelManager() {
- this(new AddressBook(), new UserPrefs());
- }
-
- @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();
- }
-
- @Override
- public void updatePerson(int filteredPersonListIndex, ReadOnlyPerson editedPerson)
- throws UniquePersonList.DuplicatePersonException {
- assert editedPerson != null;
-
- int addressBookIndex = filteredPersons.getSourceIndex(filteredPersonListIndex);
- addressBook.updatePerson(addressBookIndex, editedPerson);
- 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.containsWordIgnoreCase(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 01c9aac59099..000000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package seedu.address.model;
-
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.ReadOnlyPerson;
-import seedu.address.model.tag.Tag;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
- /**
- * Returns an unmodifiable view of the tags list.
- * This list will not contain any duplicate tags.
- */
- ObservableList 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 2b35a4a21aac..000000000000
--- a/src/main/java/seedu/address/model/person/Address.java
+++ /dev/null
@@ -1,60 +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 take any values, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String ADDRESS_VALIDATION_REGEX = "[^\\s].*";
-
- 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();
- }
-
-}
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 f26b7c5bf4af..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;
- String trimmedEmail = email.trim();
- if (!isValidEmail(trimmedEmail)) {
- throw new IllegalValueException(MESSAGE_EMAIL_CONSTRAINTS);
- }
- this.value = trimmedEmail;
- }
-
- /**
- * 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 e4c6504cb4ce..000000000000
--- a/src/main/java/seedu/address/model/person/Name.java
+++ /dev/null
@@ -1,61 +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 only contain alphanumeric characters and spaces, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String NAME_VALIDATION_REGEX = "[\\p{Alnum}][\\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;
- String trimmedName = name.trim();
- if (!isValidName(trimmedName)) {
- throw new IllegalValueException(MESSAGE_NAME_CONSTRAINTS);
- }
- this.fullName = trimmedName;
- }
-
- /**
- * 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 74ab860405ac..000000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package seedu.address.model.person;
-
-import java.util.Objects;
-
-import seedu.address.commons.util.CollectionUtil;
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * 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
- }
-
- /**
- * Creates a copy of the given ReadOnlyPerson.
- */
- public Person(ReadOnlyPerson source) {
- this(source.getName(), source.getPhone(), source.getEmail(), source.getAddress(), source.getTags());
- }
-
- public void setName(Name name) {
- assert name != null;
- this.name = name;
- }
-
- @Override
- public Name getName() {
- return name;
- }
-
- public void setPhone(Phone phone) {
- assert phone != null;
- this.phone = phone;
- }
-
- @Override
- public Phone getPhone() {
- return phone;
- }
-
- public void setEmail(Email email) {
- assert email != null;
- this.email = email;
- }
-
- @Override
- public Email getEmail() {
- return email;
- }
-
- public void setAddress(Address address) {
- assert address != null;
- this.address = address;
- }
-
- @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);
- }
-
- /**
- * Updates this person with the details of {@code replacement}.
- */
- public void resetData(ReadOnlyPerson replacement) {
- assert replacement != null;
-
- this.setName(replacement.getName());
- this.setPhone(replacement.getPhone());
- this.setEmail(replacement.getEmail());
- this.setAddress(replacement.getAddress());
- this.setTags(replacement.getTags());
- }
-
- @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 4756109125a9..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;
- String trimmedPhone = phone.trim();
- if (!isValidPhone(trimmedPhone)) {
- throw new IllegalValueException(MESSAGE_PHONE_CONSTRAINTS);
- }
- this.value = trimmedPhone;
- }
-
- /**
- * 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/ReadOnlyPerson.java b/src/main/java/seedu/address/model/person/ReadOnlyPerson.java
deleted file mode 100644
index 929fa3f70ddd..000000000000
--- a/src/main/java/seedu/address/model/person/ReadOnlyPerson.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package seedu.address.model.person;
-
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * A read-only immutable interface for a Person in the addressbook.
- * Implementations should guarantee: details are present and not null, field values are validated.
- */
-public interface ReadOnlyPerson {
-
- Name getName();
- Phone getPhone();
- Email getEmail();
- Address getAddress();
-
- /**
- * The returned TagList is a deep copy of the internal TagList,
- * changes on the returned list will not affect the person's internal tags.
- */
- UniqueTagList getTags();
-
- /**
- * Returns true if both have the same state. (interfaces cannot override .equals)
- */
- default boolean isSameStateAs(ReadOnlyPerson 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.
- */
- 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: ");
- getTags().forEach(builder::append);
- return builder.toString();
- }
-
-}
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 68a0099108b7..000000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package seedu.address.model.person;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.UnmodifiableObservableList;
-import seedu.address.commons.exceptions.DuplicateDataException;
-import seedu.address.commons.util.CollectionUtil;
-
-/**
- * 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 {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
-
- /**
- * 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);
- }
-
- /**
- * Updates the person in the list at position {@code index} with {@code editedPerson}.
- *
- * @throws DuplicatePersonException if updating the person's details causes the person to be equivalent to
- * another existing person in the list.
- * @throws IndexOutOfBoundsException if {@code index} < 0 or >= the size of the list.
- */
- public void updatePerson(int index, ReadOnlyPerson editedPerson) throws DuplicatePersonException {
- assert editedPerson != null;
-
- Person personToUpdate = internalList.get(index);
- if (!personToUpdate.equals(editedPerson) && internalList.contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- personToUpdate.resetData(editedPerson);
- // TODO: The code below is just a workaround to notify observers of the updated person.
- // The right way is to implement observable properties in the Person class.
- // Then, PersonCard should then bind its text labels to those observable properties.
- internalList.set(index, personToUpdate);
- }
-
- /**
- * 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 void setPersons(UniquePersonList replacement) {
- this.internalList.setAll(replacement.internalList);
- }
-
- public void setPersons(List extends ReadOnlyPerson> persons) throws DuplicatePersonException {
- final UniquePersonList replacement = new UniquePersonList();
- for (final ReadOnlyPerson person : persons) {
- replacement.add(new Person(person));
- }
- setPersons(replacement);
- }
-
- public UnmodifiableObservableList asObservableList() {
- return new UnmodifiableObservableList<>(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();
- }
-
- /**
- * 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 {}
-
-}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
deleted file mode 100644
index d102f72677e2..000000000000
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package seedu.address.model.util;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.person.UniquePersonList.DuplicatePersonException;
-import seedu.address.model.tag.UniqueTagList;
-
-public class SampleDataUtil {
- public static Person[] getSamplePersons() {
- try {
- return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@gmail.com"),
- new Address("Blk 30 Geylang Street 29, #06-40"),
- new UniqueTagList("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@gmail.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- new UniqueTagList("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@yahoo.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- new UniqueTagList("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@google.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- new UniqueTagList("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@outlook.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- new UniqueTagList("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@gmail.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- new UniqueTagList("colleagues"))
- };
- } catch (IllegalValueException e) {
- throw new AssertionError("sample data cannot be invalid", e);
- }
- }
-
- public static ReadOnlyAddressBook getSampleAddressBook() {
- try {
- AddressBook sampleAB = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAB.addPerson(samplePerson);
- }
- return sampleAB;
- } catch (DuplicatePersonException e) {
- throw new AssertionError("sample data cannot contain duplicate persons", e);
- }
- }
-}
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 cf5b527c063a..000000000000
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * 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 c0881a5a6483..000000000000
--- a/src/main/java/seedu/address/storage/Storage.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.util.Optional;
-
-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;
-
-/**
- * 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 632ae8a7f0ed..000000000000
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-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;
-
-/**
- * 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 d8daf509a0f1..000000000000
--- a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlElement;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.person.ReadOnlyPerson;
-import seedu.address.model.tag.Tag;
-import seedu.address.model.tag.UniqueTagList;
-
-/**
- * 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<>();
-
- /**
- * Constructs an XmlAdaptedPerson.
- * This is the no-arg constructor that is required by JAXB.
- */
- 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 462d8bbdad2d..000000000000
--- a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package seedu.address.storage;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * 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;
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException, IOException {
- return readAddressBook(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);
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
- }
-
- /**
- * 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));
- }
-
-}
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 84ed8b36233a..000000000000
--- a/src/main/java/seedu/address/ui/BrowserPanel.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package seedu.address.ui;
-
-import javafx.event.Event;
-import javafx.fxml.FXML;
-import javafx.scene.layout.AnchorPane;
-import javafx.scene.layout.Region;
-import javafx.scene.web.WebView;
-import seedu.address.commons.util.FxViewUtil;
-import seedu.address.model.person.ReadOnlyPerson;
-
-/**
- * The Browser Panel of the App.
- */
-public class BrowserPanel extends UiPart {
-
- private static final String FXML = "BrowserPanel.fxml";
-
- @FXML
- private WebView browser;
-
- /**
- * @param placeholder The AnchorPane where the BrowserPanel must be inserted
- */
- public BrowserPanel(AnchorPane placeholder) {
- super(FXML);
- placeholder.setOnKeyPressed(Event::consume); // To prevent triggering events for typing inside the
- // loaded Web page.
- FxViewUtil.applyAnchorBoundaryParameters(browser, 0.0, 0.0, 0.0, 0.0);
- placeholder.getChildren().add(browser);
- }
-
- 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 7f64572f0167..000000000000
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package seedu.address.ui;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Region;
-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 FlowPane tags;
-
- public PersonCard(ReadOnlyPerson person, int displayedIndex) {
- super(FXML);
- name.setText(person.getName().fullName);
- id.setText(displayedIndex + ". ");
- phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
- initTags(person);
- }
-
- private void initTags(ReadOnlyPerson person) {
- person.getTags().forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
- }
-}
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/task/MainApp.java
similarity index 68%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/seedu/task/MainApp.java
index 575df86ae45f..51763d28224d 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/task/MainApp.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.task;
import java.io.IOException;
import java.util.Map;
@@ -10,26 +10,26 @@
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.ConfigUtil;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.Logic;
-import seedu.address.logic.LogicManager;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.util.SampleDataUtil;
-import seedu.address.storage.Storage;
-import seedu.address.storage.StorageManager;
-import seedu.address.ui.Ui;
-import seedu.address.ui.UiManager;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.EventsCenter;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Version;
+import seedu.task.commons.events.ui.ExitAppRequestEvent;
+import seedu.task.commons.exceptions.DataConversionException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.commons.util.StringUtil;
+import seedu.task.logic.Logic;
+import seedu.task.logic.LogicManager;
+import seedu.task.model.Model;
+import seedu.task.model.ModelManager;
+import seedu.task.model.ReadOnlyTaskList;
+import seedu.task.model.TaskList;
+import seedu.task.model.UserPrefs;
+import seedu.task.model.util.SampleDataUtil;
+import seedu.task.storage.Storage;
+import seedu.task.storage.StorageManager;
+import seedu.task.ui.Ui;
+import seedu.task.ui.UiManager;
/**
* The main entry point to the application.
@@ -46,25 +46,21 @@ public class MainApp extends Application {
protected Config config;
protected UserPrefs userPrefs;
-
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing Task Manager ]===========================");
super.init();
config = initConfig(getApplicationParameter("config"));
- storage = new StorageManager(config.getAddressBookFilePath(), config.getUserPrefsFilePath());
+ storage = new StorageManager(config.getTaskManagerFilePath(), config.getUserPrefsFilePath());
userPrefs = initPrefs(config);
initLogging(config);
model = initModelManager(storage, userPrefs);
-
- logic = new LogicManager(model, storage);
-
+ logic = new LogicManager(model, storage, config);
ui = new UiManager(logic, config, userPrefs);
-
initEventsCenter();
}
@@ -74,22 +70,21 @@ private String getApplicationParameter(String parameterName) {
}
private Model initModelManager(Storage storage, UserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional taskManagerOptional;
+ ReadOnlyTaskList initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ taskManagerOptional = storage.readTaskList();
+ if (!taskManagerOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample TaskList");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = taskManagerOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
} 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 TaskList");
+ initialData = new TaskList();
} 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 TaskList");
+ initialData = new TaskList();
}
-
return new ModelManager(initialData, userPrefs);
}
@@ -114,12 +109,13 @@ protected Config initConfig(String configFilePath) {
Optional configOptional = ConfigUtil.readConfig(configFilePathUsed);
initializedConfig = configOptional.orElse(new Config());
} catch (DataConversionException e) {
- logger.warning("Config file at " + configFilePathUsed + " is not in the correct format. " +
- "Using default config properties");
+ logger.warning("Config file at " + configFilePathUsed + " is not in the correct format. "
+ + "Using default config properties");
initializedConfig = new Config();
}
- //Update config file in case it was missing to begin with or there are new/unused fields
+ // Update config file in case it was missing to begin with or there are
+ // new/unused fields
try {
ConfigUtil.saveConfig(initializedConfig, configFilePathUsed);
} catch (IOException e) {
@@ -139,15 +135,16 @@ protected UserPrefs initPrefs(Config config) {
Optional prefsOptional = storage.readUserPrefs();
initializedPrefs = prefsOptional.orElse(new UserPrefs());
} catch (DataConversionException e) {
- logger.warning("UserPrefs file at " + prefsFilePath + " is not in the correct format. " +
- "Using default user prefs");
+ logger.warning("UserPrefs file at " + prefsFilePath + " is not in the correct format. "
+ + "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 TaskManager");
initializedPrefs = new UserPrefs();
}
- //Update prefs file in case it was missing to begin with or there are new/unused fields
+ // Update prefs file in case it was missing to begin with or there are
+ // new/unused fields
try {
storage.saveUserPrefs(initializedPrefs);
} catch (IOException e) {
@@ -163,13 +160,13 @@ private void initEventsCenter() {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting Task Manager " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping Task Manager ] =============================");
ui.stop();
try {
storage.saveUserPrefs(userPrefs);
diff --git a/src/main/java/seedu/address/commons/core/ComponentManager.java b/src/main/java/seedu/task/commons/core/ComponentManager.java
similarity index 87%
rename from src/main/java/seedu/address/commons/core/ComponentManager.java
rename to src/main/java/seedu/task/commons/core/ComponentManager.java
index 05a400773ae8..0c2f68c21fa8 100644
--- a/src/main/java/seedu/address/commons/core/ComponentManager.java
+++ b/src/main/java/seedu/task/commons/core/ComponentManager.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.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/task/commons/core/Config.java
similarity index 64%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/seedu/task/commons/core/Config.java
index d4dc73132d5c..903cf9c68b81 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/seedu/task/commons/core/Config.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
import java.util.Objects;
import java.util.logging.Level;
@@ -11,11 +11,11 @@ public class Config {
public static final String DEFAULT_CONFIG_FILE = "config.json";
// Config values customizable through config file
- private String appTitle = "Address App";
+ private String appTitle = "Task Manager";
private Level logLevel = Level.INFO;
private String userPrefsFilePath = "preferences.json";
- private String addressBookFilePath = "data/addressbook.xml";
- private String addressBookName = "MyAddressBook";
+ private String taskManagerFilePath = "data/taskmanager.xml";
+ private String taskManagerName = "MyTaskManager";
public String getAppTitle() {
@@ -42,20 +42,20 @@ public void setUserPrefsFilePath(String userPrefsFilePath) {
this.userPrefsFilePath = userPrefsFilePath;
}
- public String getAddressBookFilePath() {
- return addressBookFilePath;
+ public String getTaskManagerFilePath() {
+ return taskManagerFilePath;
}
- public void setAddressBookFilePath(String addressBookFilePath) {
- this.addressBookFilePath = addressBookFilePath;
+ public void setTaskManagerFilePath(String taskManagerFilePath) {
+ this.taskManagerFilePath = taskManagerFilePath;
}
- public String getAddressBookName() {
- return addressBookName;
+ public String getTaskManagerName() {
+ return taskManagerName;
}
- public void setAddressBookName(String addressBookName) {
- this.addressBookName = addressBookName;
+ public void setTaskManagerName(String taskManagerName) {
+ this.taskManagerName = taskManagerName;
}
@@ -73,23 +73,23 @@ 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(taskManagerFilePath, o.taskManagerFilePath)
+ && Objects.equals(taskManagerName, o.taskManagerName);
}
@Override
public int hashCode() {
- return Objects.hash(appTitle, logLevel, userPrefsFilePath, addressBookFilePath, addressBookName);
+ return Objects.hash(appTitle, logLevel, userPrefsFilePath, taskManagerFilePath, taskManagerName);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("App title : " + appTitle);
+ sb.append("TaskManager name : " + 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 : " + taskManagerFilePath);
+ sb.append("\nTaskManager name : " + taskManagerName);
return sb.toString();
}
diff --git a/src/main/java/seedu/address/commons/core/EventsCenter.java b/src/main/java/seedu/task/commons/core/EventsCenter.java
similarity index 92%
rename from src/main/java/seedu/address/commons/core/EventsCenter.java
rename to src/main/java/seedu/task/commons/core/EventsCenter.java
index 4777d3f57da7..eaeb736c63e5 100644
--- a/src/main/java/seedu/address/commons/core/EventsCenter.java
+++ b/src/main/java/seedu/task/commons/core/EventsCenter.java
@@ -1,10 +1,10 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* Manages the event dispatching of the app.
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/task/commons/core/GuiSettings.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/seedu/task/commons/core/GuiSettings.java
index 846d714375e4..29e82fe108af 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/task/commons/core/GuiSettings.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
import java.awt.Point;
import java.io.Serializable;
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/task/commons/core/LogsCenter.java
similarity index 96%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/seedu/task/commons/core/LogsCenter.java
index 99ce6fc10833..14b41eb05d13 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/task/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
import java.io.IOException;
import java.util.logging.ConsoleHandler;
@@ -8,7 +8,7 @@
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* Configures and manages loggers and handlers, including their logging level
@@ -20,7 +20,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 = "taskmanager.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/task/commons/core/Messages.java b/src/main/java/seedu/task/commons/core/Messages.java
new file mode 100644
index 000000000000..3089ecf69d48
--- /dev/null
+++ b/src/main/java/seedu/task/commons/core/Messages.java
@@ -0,0 +1,15 @@
+package seedu.task.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 listed!";
+ //@@author A0164212U
+ public static final String MESSSAGE_INVALID_TIMING_ORDER = "The start and end times are not in chronological order";
+
+}
diff --git a/src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java b/src/main/java/seedu/task/commons/core/UnmodifiableObservableList.java
similarity index 99%
rename from src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java
rename to src/main/java/seedu/task/commons/core/UnmodifiableObservableList.java
index a5b6835ac617..ddc9b244c217 100644
--- a/src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java
+++ b/src/main/java/seedu/task/commons/core/UnmodifiableObservableList.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
import java.text.Collator;
import java.util.Collection;
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/task/commons/core/Version.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/seedu/task/commons/core/Version.java
index 9023b29ae3d0..0622383ddd2c 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/seedu/task/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.task.commons.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/src/main/java/seedu/address/commons/events/BaseEvent.java b/src/main/java/seedu/task/commons/events/BaseEvent.java
similarity index 90%
rename from src/main/java/seedu/address/commons/events/BaseEvent.java
rename to src/main/java/seedu/task/commons/events/BaseEvent.java
index daf9144f95c9..496cedeb9889 100644
--- a/src/main/java/seedu/address/commons/events/BaseEvent.java
+++ b/src/main/java/seedu/task/commons/events/BaseEvent.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.events;
+package seedu.task.commons.events;
public abstract class BaseEvent {
diff --git a/src/main/java/seedu/task/commons/events/model/TaskListChangedEvent.java b/src/main/java/seedu/task/commons/events/model/TaskListChangedEvent.java
new file mode 100644
index 000000000000..fbde5acc48ba
--- /dev/null
+++ b/src/main/java/seedu/task/commons/events/model/TaskListChangedEvent.java
@@ -0,0 +1,19 @@
+package seedu.task.commons.events.model;
+
+import seedu.task.commons.events.BaseEvent;
+import seedu.task.model.ReadOnlyTaskList;
+
+/** Indicates the TaskList in the model has changed*/
+public class TaskListChangedEvent extends BaseEvent {
+
+ public final ReadOnlyTaskList data;
+
+ public TaskListChangedEvent(ReadOnlyTaskList data) {
+ this.data = data;
+ }
+
+ @Override
+ public String toString() {
+ return "number of tasks " + data.getTaskList().size() + ", number of tags " + data.getTagList().size();
+ }
+}
diff --git a/src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java b/src/main/java/seedu/task/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/task/commons/events/storage/DataSavingExceptionEvent.java
index 51cf8ce68a76..ebb6c6ae2d50 100644
--- a/src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java
+++ b/src/main/java/seedu/task/commons/events/storage/DataSavingExceptionEvent.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.events.storage;
+package seedu.task.commons.events.storage;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* Indicates an exception during a file saving
diff --git a/src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java b/src/main/java/seedu/task/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/task/commons/events/ui/ExitAppRequestEvent.java
index 9af6194543a3..c44de8330c13 100644
--- a/src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java
+++ b/src/main/java/seedu/task/commons/events/ui/ExitAppRequestEvent.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.events.ui;
+package seedu.task.commons.events.ui;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* Indicates a request for App termination
diff --git a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java b/src/main/java/seedu/task/commons/events/ui/JumpToListRequestEvent.java
similarity index 80%
rename from src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java
rename to src/main/java/seedu/task/commons/events/ui/JumpToListRequestEvent.java
index 0580d27aecf5..31ee4f2fa40f 100644
--- a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java
+++ b/src/main/java/seedu/task/commons/events/ui/JumpToListRequestEvent.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.events.ui;
+package seedu.task.commons.events.ui;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* Indicates a request to jump to the list of persons
diff --git a/src/main/java/seedu/address/commons/events/ui/NewResultAvailableEvent.java b/src/main/java/seedu/task/commons/events/ui/NewResultAvailableEvent.java
similarity index 79%
rename from src/main/java/seedu/address/commons/events/ui/NewResultAvailableEvent.java
rename to src/main/java/seedu/task/commons/events/ui/NewResultAvailableEvent.java
index a6d5274a97e0..ceea35c27c8a 100644
--- a/src/main/java/seedu/address/commons/events/ui/NewResultAvailableEvent.java
+++ b/src/main/java/seedu/task/commons/events/ui/NewResultAvailableEvent.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.events.ui;
+package seedu.task.commons.events.ui;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* Indicates that a new result is available.
diff --git a/src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java b/src/main/java/seedu/task/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/task/commons/events/ui/ShowHelpRequestEvent.java
index a7e40940b2c7..646fe04ba861 100644
--- a/src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java
+++ b/src/main/java/seedu/task/commons/events/ui/ShowHelpRequestEvent.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.events.ui;
+package seedu.task.commons.events.ui;
-import seedu.address.commons.events.BaseEvent;
+import seedu.task.commons.events.BaseEvent;
/**
* An event requesting to view the help page.
diff --git a/src/main/java/seedu/task/commons/events/ui/TaskPanelSelectionChangedEvent.java b/src/main/java/seedu/task/commons/events/ui/TaskPanelSelectionChangedEvent.java
new file mode 100644
index 000000000000..a899fbd46f07
--- /dev/null
+++ b/src/main/java/seedu/task/commons/events/ui/TaskPanelSelectionChangedEvent.java
@@ -0,0 +1,26 @@
+package seedu.task.commons.events.ui;
+
+import seedu.task.commons.events.BaseEvent;
+import seedu.task.model.task.ReadOnlyTask;
+
+/**
+ * Represents a selection change in the Task List Panel
+ */
+public class TaskPanelSelectionChangedEvent extends BaseEvent {
+
+
+ private final ReadOnlyTask newSelection;
+
+ public TaskPanelSelectionChangedEvent(ReadOnlyTask newSelection) {
+ this.newSelection = newSelection;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName();
+ }
+
+ public ReadOnlyTask getNewSelection() {
+ return newSelection;
+ }
+}
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/task/commons/exceptions/DataConversionException.java
similarity index 84%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/task/commons/exceptions/DataConversionException.java
index 1f689bd8e3f9..6ece0d7a087b 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/task/commons/exceptions/DataConversionException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.task.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/task/commons/exceptions/DuplicateDataException.java
similarity index 85%
rename from src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java
rename to src/main/java/seedu/task/commons/exceptions/DuplicateDataException.java
index 17aa63d5020c..3edf3124f8f5 100644
--- a/src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java
+++ b/src/main/java/seedu/task/commons/exceptions/DuplicateDataException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.task.commons.exceptions;
/**
* Signals an error caused by duplicate data where there should be none.
diff --git a/src/main/java/seedu/task/commons/exceptions/IllegalTimingOrderException.java b/src/main/java/seedu/task/commons/exceptions/IllegalTimingOrderException.java
new file mode 100644
index 000000000000..0dd912c5d489
--- /dev/null
+++ b/src/main/java/seedu/task/commons/exceptions/IllegalTimingOrderException.java
@@ -0,0 +1,14 @@
+//@@author A0164212U
+package seedu.task.commons.exceptions;
+
+/**
+ * Signals that start timing is after end timing.
+ */
+public class IllegalTimingOrderException extends Exception {
+ /**
+ * @param message should contain relevant information on the failed constraint(s)
+ */
+ public IllegalTimingOrderException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/task/commons/exceptions/IllegalValueException.java
similarity index 88%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/seedu/task/commons/exceptions/IllegalValueException.java
index a473b43bd86f..736ff8eb63d3 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/seedu/task/commons/exceptions/IllegalValueException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.task.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/task/commons/util/AppUtil.java
similarity index 81%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/task/commons/util/AppUtil.java
index 649cc19aaeda..e1f36b8637ff 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/task/commons/util/AppUtil.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.task.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/task/commons/util/CollectionUtil.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/task/commons/util/CollectionUtil.java
index 3b7ba0b049c4..c339bd0d4970 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/task/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.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/task/commons/util/ConfigUtil.java
similarity index 76%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/task/commons/util/ConfigUtil.java
index 7eb770dba3e3..d8444c9a86bd 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/task/commons/util/ConfigUtil.java
@@ -1,10 +1,10 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import java.io.IOException;
import java.util.Optional;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.exceptions.DataConversionException;
/**
* A class for accessing the Config File.
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/task/commons/util/FileUtil.java
similarity index 81%
rename from src/main/java/seedu/address/commons/util/FileUtil.java
rename to src/main/java/seedu/task/commons/util/FileUtil.java
index 3e1eb4d9ff6e..c9850e31ec6c 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/task/commons/util/FileUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import java.io.File;
import java.io.IOException;
@@ -85,4 +85,21 @@ public static String getPath(String pathWithForwardSlash) {
return pathWithForwardSlash.replace("/", File.separator);
}
+ //@@author A0163559U
+ /**
+ * Compares the contents of two files.
+ * @param f1 file 1
+ * @param f2 file 2
+ * @return true if file contents are identical
+ * @throws IOException
+ */
+ public static boolean isFileContentSame(File f1, File f2) throws IOException {
+ String fileAsString1 = readFromFile(f1);
+ String fileAsString2 = readFromFile(f2);
+ System.out.println(fileAsString1);
+ System.out.println(fileAsString2);
+ return fileAsString1.equals(fileAsString2);
+ }
+ //@@author
+
}
diff --git a/src/main/java/seedu/address/commons/util/FxViewUtil.java b/src/main/java/seedu/task/commons/util/FxViewUtil.java
similarity index 95%
rename from src/main/java/seedu/address/commons/util/FxViewUtil.java
rename to src/main/java/seedu/task/commons/util/FxViewUtil.java
index 9a1a8833f5c7..da495b64e0f6 100644
--- a/src/main/java/seedu/address/commons/util/FxViewUtil.java
+++ b/src/main/java/seedu/task/commons/util/FxViewUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.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/task/commons/util/JsonUtil.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/seedu/task/commons/util/JsonUtil.java
index 4a997dade9e6..732974c78fd0 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/task/commons/util/JsonUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import java.io.File;
import java.io.IOException;
@@ -17,8 +17,8 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.DataConversionException;
/**
* Converts a Java object instance to JSON and vice versa
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/task/commons/util/StringUtil.java
similarity index 98%
rename from src/main/java/seedu/address/commons/util/StringUtil.java
rename to src/main/java/seedu/task/commons/util/StringUtil.java
index 7f1998fa4c51..9b50798eb2e7 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/seedu/task/commons/util/StringUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/src/main/java/seedu/address/commons/util/UrlUtil.java b/src/main/java/seedu/task/commons/util/UrlUtil.java
similarity index 94%
rename from src/main/java/seedu/address/commons/util/UrlUtil.java
rename to src/main/java/seedu/task/commons/util/UrlUtil.java
index 5dcf38061d2f..90443a69f2d1 100644
--- a/src/main/java/seedu/address/commons/util/UrlUtil.java
+++ b/src/main/java/seedu/task/commons/util/UrlUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import java.net.URL;
diff --git a/src/main/java/seedu/address/commons/util/XmlUtil.java b/src/main/java/seedu/task/commons/util/XmlUtil.java
similarity index 98%
rename from src/main/java/seedu/address/commons/util/XmlUtil.java
rename to src/main/java/seedu/task/commons/util/XmlUtil.java
index fc0bbda18231..e738ed7f98d7 100644
--- a/src/main/java/seedu/address/commons/util/XmlUtil.java
+++ b/src/main/java/seedu/task/commons/util/XmlUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.task.commons.util;
import java.io.File;
import java.io.FileNotFoundException;
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/task/logic/Logic.java
similarity index 59%
rename from src/main/java/seedu/address/logic/Logic.java
rename to src/main/java/seedu/task/logic/Logic.java
index 209485f2a77a..6559a830a549 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/task/logic/Logic.java
@@ -1,9 +1,9 @@
-package seedu.address.logic;
+package seedu.task.logic;
import javafx.collections.ObservableList;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.person.ReadOnlyPerson;
+import seedu.task.logic.commands.CommandResult;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.task.ReadOnlyTask;
/**
* API of the Logic component
@@ -17,7 +17,7 @@ public interface Logic {
*/
CommandResult execute(String commandText) throws CommandException;
- /** Returns the filtered list of persons */
- ObservableList getFilteredPersonList();
+ /** Returns the filtered list of tasks */
+ ObservableList getFilteredTaskList();
}
diff --git a/src/main/java/seedu/task/logic/LogicManager.java b/src/main/java/seedu/task/logic/LogicManager.java
new file mode 100644
index 000000000000..b0c3e7c95f37
--- /dev/null
+++ b/src/main/java/seedu/task/logic/LogicManager.java
@@ -0,0 +1,49 @@
+package seedu.task.logic;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import seedu.task.commons.core.ComponentManager;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.CommandResult;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.logic.parser.Parser;
+import seedu.task.model.Model;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.storage.Storage;
+
+/**
+ * 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 Storage storage;
+ private final Config config;
+ private final Parser parser;
+
+ public LogicManager(Model model, Storage storage, Config config) {
+ this.model = model;
+ this.storage = storage;
+ this.config = config;
+ this.parser = new Parser();
+ }
+
+ @Override
+ public CommandResult execute(String commandText) throws CommandException {
+ logger.info("----------------[USER COMMAND][" + commandText + "]");
+ Command command = parser.parseCommand(commandText);
+ command.setData(model);
+ command.setStorage(storage);
+ command.setConfig(config);
+ return command.execute();
+ }
+
+ @Override
+ public ObservableList getFilteredTaskList() {
+ return model.getFilteredTaskList();
+ }
+}
diff --git a/src/main/java/seedu/task/logic/commands/AddCommand.java b/src/main/java/seedu/task/logic/commands/AddCommand.java
new file mode 100644
index 000000000000..f9f1b14d13fb
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/AddCommand.java
@@ -0,0 +1,85 @@
+package seedu.task.logic.commands;
+
+import static seedu.task.commons.core.Messages.MESSSAGE_INVALID_TIMING_ORDER;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.IllegalTimingOrderException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.tag.Tag;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.model.task.UniqueTaskList;
+
+/**
+ * Adds a task to the task manager.
+ */
+public class AddCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(AddCommand.class);
+ public static final String COMMAND_WORD = "add";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a task to the task manager. "
+ + "Parameters: TASK_NAME p/PRIORITY_LEVEL sd/DATE ed/DATE [t/TAG]...\n"
+ + "Example: " + COMMAND_WORD
+ + " Study for midterm p/1 sd/04/03/2017 ed/06/03/2017 t/study t/midterm";
+
+ public static final String MESSAGE_SUCCESS = "New task added: %1$s";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager";
+
+ private final Task toAdd;
+ //@@author A0164212U
+ /**
+ * Creates an AddCommand using raw values.
+ *
+ * @throws IllegalValueException if any of the raw values are invalid
+ */
+ public AddCommand(String name, String priority, String startTiming, String endTiming,
+ String recurFreq, Set tags)
+ throws IllegalValueException, IllegalTimingOrderException {
+ final Set tagSet = new HashSet<>();
+ for (String tagName : tags) {
+ tagSet.add(new Tag(tagName));
+ }
+ boolean recurring = (recurFreq != null);
+
+ this.toAdd = new Task(
+ new Description(name),
+ new Priority(priority),
+ new Timing(startTiming),
+ new Timing(endTiming),
+ new UniqueTagList(tagSet),
+ recurring,
+ new RecurringFrequency(recurFreq)
+ );
+ if (!Timing.checkTimingOrder(toAdd.getStartTiming(), toAdd.getEndTiming())) {
+ logger.warning("Timing is not in the correct order");
+ throw new IllegalTimingOrderException(MESSSAGE_INVALID_TIMING_ORDER);
+ }
+ }
+
+ public AddCommand(ReadOnlyTask task) {
+ this.toAdd = (Task) task;
+ }
+ //@@author
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ try {
+ model.addTask(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ } catch (UniqueTaskList.DuplicateTaskException e) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ }
+
+ }
+}
diff --git a/src/main/java/seedu/task/logic/commands/ClearCommand.java b/src/main/java/seedu/task/logic/commands/ClearCommand.java
new file mode 100644
index 000000000000..c7eafaf77366
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/ClearCommand.java
@@ -0,0 +1,22 @@
+package seedu.task.logic.commands;
+
+import seedu.task.model.TaskList;
+
+/**
+ * Clears the task manager.
+ */
+public class ClearCommand extends Command {
+
+ public static final String COMMAND_WORD = "clear";
+ public static final String MESSAGE_SUCCESS = "Task Manager has been cleared!";
+
+
+ @Override
+ public CommandResult execute() {
+ assert model != null;
+ TaskList old = new TaskList(model.getTaskList());
+ model.getUndoStack().push(old);
+ model.resetData(new TaskList());
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/task/logic/commands/Command.java
similarity index 53%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/seedu/task/logic/commands/Command.java
index 828a7e8a1728..fb4a5985d925 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/task/logic/commands/Command.java
@@ -1,23 +1,27 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
-import seedu.address.commons.core.Messages;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.Messages;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.Model;
+import seedu.task.storage.Storage;
/**
* Represents a command with hidden internal logic and the ability to be executed.
*/
public abstract class Command {
protected Model model;
+ protected Storage storage;
+ protected Config config;
/**
- * 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);
}
/**
@@ -36,4 +40,13 @@ public static String getMessageForPersonListShownSummary(int displaySize) {
public void setData(Model model) {
this.model = model;
}
+ //@@author A0163559U
+ public void setConfig(Config config) {
+ this.config = config;
+ }
+
+ public void setStorage(Storage storage) {
+ this.storage = storage;
+ }
+ //@@author
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/task/logic/commands/CommandResult.java
similarity index 87%
rename from src/main/java/seedu/address/logic/commands/CommandResult.java
rename to src/main/java/seedu/task/logic/commands/CommandResult.java
index f46f2f31353e..dcc3461641a5 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/task/logic/commands/CommandResult.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
/**
* Represents the result of a command execution.
diff --git a/src/main/java/seedu/task/logic/commands/CompleteCommand.java b/src/main/java/seedu/task/logic/commands/CompleteCommand.java
new file mode 100644
index 000000000000..60210d0d2a7d
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/CompleteCommand.java
@@ -0,0 +1,144 @@
+//@@author A0113795Y
+package seedu.task.logic.commands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.core.UnmodifiableObservableList;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.logic.parser.ParserUtil;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.EditTaskDescriptor;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.model.task.UniqueTaskList;
+
+/**
+ * Change the task status to completed
+ */
+
+public class CompleteCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(CompleteCommand.class);
+ public static final String COMMAND_WORD = "complete";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Mark the task identified by the index number."
+ + "used in the last task lisitng as completed.\n"
+ + "Parameter: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 2";
+
+ public static final String MESSAGE_COMPLETE_TASK_SUCCESS = "Completed task: %1$s";
+ public static final String MESSAGE_DUPLICATE_TAG = "This tag already exists in the tag list";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
+ public static final String MESSAGE_TAG_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_NULL_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+
+ public final int targetIndex;
+ public final EditTaskDescriptor completeTaskDescriptor;
+
+ public CompleteCommand(int targetIndex) {
+ assert targetIndex > 0;
+
+ this.targetIndex = targetIndex - 1;
+ this.completeTaskDescriptor = new EditTaskDescriptor();
+
+ List list = new ArrayList<>();
+ list.add("complete");
+ try {
+ this.completeTaskDescriptor.setTags(parseTagsForComplete(ParserUtil.toSet(Optional.of(list))));
+ } catch (IllegalValueException e) {
+ e.printStackTrace();
+ }
+ }
+ //@@author
+
+ //@@author A0164212U
+ @Override
+ public CommandResult execute() throws CommandException {
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ if (lastShownList.size() <= targetIndex) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToComplete = lastShownList.get(targetIndex);
+ Task newTask = null;
+ Task completedTask;
+
+ try {
+ if (taskToComplete.isRecurring()) {
+ newTask = Task.extractOccurrence(taskToComplete);
+ model.addTask(newTask);
+ completedTask = createCompletedTask(newTask, completeTaskDescriptor);
+ int newIndex = model.getFilteredTaskList().indexOf(newTask);
+ completedTask.setComplete();
+ model.updateTask(newIndex, completedTask);
+ model.updateFilteredListToShowAll();
+ logger.info(MESSAGE_COMPLETE_TASK_SUCCESS);
+ return new CommandResult(String.format(MESSAGE_COMPLETE_TASK_SUCCESS, newTask));
+ } else {
+ completedTask = createCompletedTask(taskToComplete, completeTaskDescriptor);
+ completedTask.setComplete();
+ model.updateTask(targetIndex, completedTask);
+ model.updateFilteredListToShowAll();
+ logger.info(MESSAGE_COMPLETE_TASK_SUCCESS);
+ return new CommandResult(String.format(MESSAGE_COMPLETE_TASK_SUCCESS, taskToComplete));
+ }
+ } catch (UniqueTaskList.DuplicateTaskException dpe) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ }
+ //@@author
+ //@@author A0113795Y
+ /**
+ * Creates and returns a {@code Task} with the details of {@code taskToComplete}
+ * edited with {@code editTaskDescriptor}.
+ */
+ private static Task createCompletedTask(ReadOnlyTask taskToComplete,
+ EditTaskDescriptor editTaskDescriptor) throws CommandException {
+ assert taskToComplete != null;
+
+ Description updatedDescription = editTaskDescriptor.getDescription().orElseGet(taskToComplete::getDescription);
+ Priority updatedPriority = editTaskDescriptor.getPriority().orElseGet(taskToComplete::getPriority);
+ Timing updatedStartDate = editTaskDescriptor.getStartTiming().orElseGet(taskToComplete::getStartTiming);
+ Timing updatedEndDate = editTaskDescriptor.getEndTiming().orElseGet(taskToComplete::getEndTiming);
+ UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToComplete::getTags);
+ boolean updatedRecurring = editTaskDescriptor.isRecurring().orElseGet(taskToComplete::isRecurring);
+ RecurringFrequency updatedFrequency = editTaskDescriptor.getFrequency().orElseGet(taskToComplete::getFrequency);
+
+ updatedStartDate.setTiming(updatedStartDate.toString());
+ updatedEndDate.setTiming(updatedEndDate.toString());
+
+ Task ret;
+ try {
+ ret = new Task(updatedDescription, updatedPriority, updatedStartDate,
+ updatedEndDate, updatedTags, updatedRecurring, updatedFrequency);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ ret.setComplete();
+ return ret;
+ }
+
+ /**
+ * Parses {@code Collection tags} into an {@code Optional} if {@code tags} is non-empty.
+ * If {@code tags} contain only one element which is an empty string, it will be parsed into a
+ * {@code Optional} containing zero tags.
+ */
+ private Optional parseTagsForComplete(Collection tags) throws IllegalValueException {
+ Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
+ return Optional.of(ParserUtil.parseTags(tagSet));
+ }
+}
diff --git a/src/main/java/seedu/task/logic/commands/DeleteCommand.java b/src/main/java/seedu/task/logic/commands/DeleteCommand.java
new file mode 100644
index 000000000000..96cb1dd25efa
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/DeleteCommand.java
@@ -0,0 +1,79 @@
+package seedu.task.logic.commands;
+
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.core.UnmodifiableObservableList;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.UniqueTaskList.DuplicateTaskException;
+import seedu.task.model.task.UniqueTaskList.TaskNotFoundException;
+
+/**
+ * Deletes a task identified using it's last displayed index from the task manager.
+ */
+public class DeleteCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(DeleteCommand.class);
+
+ public static final String COMMAND_WORD = "delete";
+ public static final String COMMAND_WORD_REC = "deletethis";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the task identified by the index number used in the last task listing.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted Task: %1$s";
+ public static final String MESSAGE_MISSING_TASK = "The target task cannot be missing";
+ public static final String MESSAGE_NULL_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+
+ public final int targetIndex;
+ public final boolean isSpecific;
+
+ public DeleteCommand(int targetIndex, boolean isSpecific) {
+ this.targetIndex = targetIndex;
+ this.isSpecific = isSpecific;
+ }
+
+ //@@author A0164212U
+ @Override
+ public CommandResult execute() throws CommandException {
+
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+
+ if (lastShownList.size() < targetIndex) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToDelete = lastShownList.get(targetIndex - 1);
+ Task deleteOccurrence = null;
+
+ if (isSpecific && taskToDelete.getOccurrences().size() > 1) {
+ Task taskToAdd = new Task(taskToDelete);
+ try {
+ deleteOccurrence = Task.extractOccurrence(taskToDelete);
+ model.deleteThisTask(taskToDelete, taskToAdd);
+ logger.info("Deleting specific instance of recurring task");
+ return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, deleteOccurrence));
+ } catch (DuplicateTaskException e) {
+ throw new CommandException(AddCommand.MESSAGE_DUPLICATE_TASK);
+ } catch (TaskNotFoundException tnfe) {
+ assert false : MESSAGE_MISSING_TASK;
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ } else {
+ try {
+ model.deleteTask(taskToDelete);
+ } catch (TaskNotFoundException tnfe) {
+ assert false : MESSAGE_MISSING_TASK;
+ }
+ }
+ return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete));
+ }
+
+}
diff --git a/src/main/java/seedu/task/logic/commands/EditCommand.java b/src/main/java/seedu/task/logic/commands/EditCommand.java
new file mode 100644
index 000000000000..2c40b7112b98
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/EditCommand.java
@@ -0,0 +1,133 @@
+//@@authro A0113795Y
+package seedu.task.logic.commands;
+
+import static seedu.task.commons.core.Messages.MESSSAGE_INVALID_TIMING_ORDER;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.exceptions.IllegalTimingOrderException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.EditTaskDescriptor;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.model.task.UniqueTaskList;
+
+/**
+ * Edits the details of an existing task in the task manager.
+ */
+public class EditCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(EditCommand.class);
+ public static final String COMMAND_WORD = "edit";
+ public static final String COMMAND_WORD_REC = "editthis";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the task identified "
+ + "by the index number used in the last task listing. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer)"
+ + "[DESCRIPTION] [p/PRIORITY] [sd/START_DATE] [ed/END_DATE] [t/TAG]...\n"
+ + "Example: " + COMMAND_WORD + " 1 p/2 sd/13/03/2017";
+
+ public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
+ public static final String MESSAGE_NULL_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+
+ private final int filteredTaskListIndex;
+ private final EditTaskDescriptor editTaskDescriptor;
+ private boolean isSpecific;
+
+ /**
+ * @param filteredTaskListIndex the index of the task in the filtered task list to edit
+ * @param editTaskDescriptor details to edit the task with
+ */
+ public EditCommand(int filteredTaskListIndex, EditTaskDescriptor editTaskDescriptor, boolean isSpecific) {
+ assert filteredTaskListIndex > 0;
+ assert editTaskDescriptor != null;
+
+ // converts filteredTaskListIndex from one-based to zero-based.
+ this.filteredTaskListIndex = filteredTaskListIndex - 1;
+ this.editTaskDescriptor = new EditTaskDescriptor(editTaskDescriptor);
+ this.isSpecific = isSpecific;
+ }
+ //@@author
+ //@@author A0164212U
+ @Override
+ public CommandResult execute() throws CommandException {
+ List lastShownList = model.getFilteredTaskList();
+
+ if (filteredTaskListIndex >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToEdit = lastShownList.get(filteredTaskListIndex);
+ Task newTask = null;
+ Task editedTask;
+
+ try {
+ if (isSpecific && taskToEdit.isRecurring()) {
+ newTask = Task.extractOccurrence(taskToEdit);
+ ReadOnlyTask copyRecurTask = new Task(taskToEdit);
+ editedTask = createEditedTask(newTask, editTaskDescriptor);
+ model.updateThisTask(filteredTaskListIndex, copyRecurTask, editedTask);
+ logger.info("Editing a specific occurrence of a recurring task");
+ } else {
+ editedTask = createEditedTask(taskToEdit, editTaskDescriptor);
+ model.updateTask(filteredTaskListIndex, editedTask);
+ }
+ } catch (IllegalTimingOrderException e) {
+ throw new CommandException(MESSSAGE_INVALID_TIMING_ORDER);
+ } catch (UniqueTaskList.DuplicateTaskException dpe) {
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+
+ model.updateFilteredListToShowAll();
+ logger.info(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
+ return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
+ }
+ //@@author
+
+ /**
+ * Creates and returns a {@code Task} with the details of {@code taskToEdit}
+ * edited with {@code editTaskDescriptor}.
+ * @throws IllegalTimingOrderException
+ * @throws CommandException
+ */
+ private static Task createEditedTask(ReadOnlyTask taskToEdit,
+ EditTaskDescriptor editTaskDescriptor) throws IllegalTimingOrderException, CommandException {
+ assert taskToEdit != null;
+
+ Description updatedDescription = editTaskDescriptor.getDescription().orElseGet(taskToEdit::getDescription);
+ Priority updatedPriority = editTaskDescriptor.getPriority().orElseGet(taskToEdit::getPriority);
+ Timing updatedStartDate = editTaskDescriptor.getStartTiming().orElseGet(taskToEdit::getStartTiming);
+ Timing updatedEndDate = editTaskDescriptor.getEndTiming().orElseGet(taskToEdit::getEndTiming);
+ UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToEdit::getTags);
+ boolean updatedRecurring = editTaskDescriptor.isRecurring().orElseGet(taskToEdit::isRecurring);
+ RecurringFrequency updatedFrequency = editTaskDescriptor.getFrequency().orElseGet(taskToEdit::getFrequency);
+
+ updatedStartDate.setTiming(updatedStartDate.toString());
+ updatedEndDate.setTiming(updatedEndDate.toString());
+
+ if (!Timing.checkTimingOrder(updatedStartDate, updatedEndDate)) {
+ throw new IllegalTimingOrderException(MESSSAGE_INVALID_TIMING_ORDER);
+ }
+
+ try {
+ return new Task(updatedDescription, updatedPriority, updatedStartDate,
+ updatedEndDate, updatedTags, updatedRecurring, updatedFrequency);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/task/logic/commands/ExitCommand.java
similarity index 67%
rename from src/main/java/seedu/address/logic/commands/ExitCommand.java
rename to src/main/java/seedu/task/logic/commands/ExitCommand.java
index fbd1beb2966e..86b7818e8081 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/task/logic/commands/ExitCommand.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
-import seedu.address.commons.core.EventsCenter;
-import seedu.address.commons.events.ui.ExitAppRequestEvent;
+import seedu.task.commons.core.EventsCenter;
+import seedu.task.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 Task Manager as requested ...";
@Override
public CommandResult execute() {
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/task/logic/commands/FindCommand.java
similarity index 59%
rename from src/main/java/seedu/address/logic/commands/FindCommand.java
rename to src/main/java/seedu/task/logic/commands/FindCommand.java
index 1d61bf6cc857..a3d489875cdd 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/task/logic/commands/FindCommand.java
@@ -1,19 +1,19 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
import java.util.Set;
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
+ * Finds and lists all tasks in manager 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 "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose frequency 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";
+ + "Example: " + COMMAND_WORD + " study cs2103 tutorial";
private final Set keywords;
@@ -23,8 +23,8 @@ public FindCommand(Set keywords) {
@Override
public CommandResult execute() {
- model.updateFilteredPersonList(keywords);
- return new CommandResult(getMessageForPersonListShownSummary(model.getFilteredPersonList().size()));
+ model.updateFilteredTaskList(keywords);
+ return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size()));
}
}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/task/logic/commands/HelpCommand.java
similarity index 79%
rename from src/main/java/seedu/address/logic/commands/HelpCommand.java
rename to src/main/java/seedu/task/logic/commands/HelpCommand.java
index cc5a6b5463ab..50b679297f7f 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/task/logic/commands/HelpCommand.java
@@ -1,8 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
-
-import seedu.address.commons.core.EventsCenter;
-import seedu.address.commons.events.ui.ShowHelpRequestEvent;
+import seedu.task.commons.core.EventsCenter;
+import seedu.task.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/task/logic/commands/IncorrectCommand.java
similarity index 81%
rename from src/main/java/seedu/address/logic/commands/IncorrectCommand.java
rename to src/main/java/seedu/task/logic/commands/IncorrectCommand.java
index 9c05b48cce9f..831bd0c523ce 100644
--- a/src/main/java/seedu/address/logic/commands/IncorrectCommand.java
+++ b/src/main/java/seedu/task/logic/commands/IncorrectCommand.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.task.logic.commands.exceptions.CommandException;
/**
* Represents an incorrect command. Upon execution, throws a CommandException with feedback to the user.
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/task/logic/commands/ListCommand.java
similarity index 62%
rename from src/main/java/seedu/address/logic/commands/ListCommand.java
rename to src/main/java/seedu/task/logic/commands/ListCommand.java
index bb0dd54a8bab..7fe3b9702289 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/task/logic/commands/ListCommand.java
@@ -1,14 +1,14 @@
-package seedu.address.logic.commands;
+package seedu.task.logic.commands;
/**
- * Lists all persons in the address book to the user.
+ * Lists all tasks 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 static final String MESSAGE_SUCCESS = "Listed all tasks";
@Override
diff --git a/src/main/java/seedu/task/logic/commands/LoadCommand.java b/src/main/java/seedu/task/logic/commands/LoadCommand.java
new file mode 100644
index 000000000000..b74180c43e27
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/LoadCommand.java
@@ -0,0 +1,93 @@
+//@@author A0163559U
+package seedu.task.logic.commands;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.DataConversionException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.ReadOnlyTaskList;
+
+/**
+ * Loads task data from the specified directory and file.
+ */
+public class LoadCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(LoadCommand.class);
+
+ public static final String COMMAND_WORD = "load";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Loads all tasks from specified directory and file name. "
+ + "Parameters: LOAD_LOCATION\n"
+ + "Example: " + COMMAND_WORD
+ + " /Users/username/Documents/TaskManager/taskmanager.xml";
+
+ public static final String MESSAGE_SUCCESS = "Tasks loaded from location: %1$s";
+ public static final String MESSAGE_INVALID_LOAD_LOCATION = "This load location is invalid: %1$s";
+ public static final String MESSAGE_NULL_LOAD_LOCATION = "A load location must be specified.";
+ public static final String MESSAGE_DIRECTORY_LOAD_LOCATION = "A load location must also include the file name.";
+ public static final String MESSAGE_LOAD_IO_EXCEPTION = "Failed to load file in location: %1$s";
+
+ private final File toLoad;
+ /**
+ * Creates a LoadCommand using raw values.
+ *
+ * @throws IllegalValueException if the load location is invalid
+ * @throws IOException
+ */
+ public LoadCommand(String fileAsString) throws IllegalValueException {
+ if (fileAsString == null || fileAsString.equals("")) {
+ throw new IllegalValueException(MESSAGE_NULL_LOAD_LOCATION);
+ }
+
+ this.toLoad = new File(fileAsString.trim());
+
+ if (!toLoad.exists()) {
+ throw new IllegalValueException(String.format(MESSAGE_INVALID_LOAD_LOCATION, fileAsString));
+ }
+
+ if (toLoad.isDirectory()) {
+ throw new IllegalValueException(MESSAGE_DIRECTORY_LOAD_LOCATION);
+ }
+
+ assert toLoad.exists();
+
+ }
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ assert config != null;
+ logger.info("Executing load command with " + toLoad.toString());
+
+ try {
+ Optional newTaskList = storage.loadTaskListFromNewLocation(toLoad);
+ if (newTaskList.isPresent()) {
+ model.resetData(newTaskList.get());
+ }
+ } catch (FileNotFoundException | DataConversionException e1) {
+ logger.warning("Failed to execute load.");
+ throw new CommandException(MESSAGE_LOAD_IO_EXCEPTION);
+ }
+
+ config.setTaskManagerFilePath(toLoad.toString());
+
+ try {
+ ConfigUtil.saveConfig(config, Config.DEFAULT_CONFIG_FILE);
+ } catch (IOException e) {
+ logger.warning("Failed to execute load.");
+ throw new CommandException(String.format(MESSAGE_LOAD_IO_EXCEPTION, toLoad.toString()));
+ }
+ logger.info("Execute load succeeded");
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toLoad.toString()));
+
+ }
+
+}
diff --git a/src/main/java/seedu/task/logic/commands/PrioritizeCommand.java b/src/main/java/seedu/task/logic/commands/PrioritizeCommand.java
new file mode 100644
index 000000000000..abe4aa26acaf
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/PrioritizeCommand.java
@@ -0,0 +1,99 @@
+//@@author A0113795Y
+package seedu.task.logic.commands;
+
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.core.Messages;
+import seedu.task.commons.core.UnmodifiableObservableList;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.exceptions.CommandException;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.EditTaskDescriptor;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.ReadOnlyTask;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Task;
+import seedu.task.model.task.Timing;
+import seedu.task.model.task.UniqueTaskList;
+
+public class PrioritizeCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(PrioritizeCommand.class);
+ public static final String COMMAND_WORD = "prioritize";
+ public static final String MESSAGE_PRIORITY_CONSTRAINTS = "Task priority should be between 1-3";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Change the priority of the task identified "
+ + "by the index number used in the last task lisitng as completed.\n"
+ + "Parameter: INDEX (must be a positive integer) NEW_PRIORITY_LEVEL (integer from 1 to 3)\n"
+ + "Example: " + COMMAND_WORD + " 2" + " 1";
+
+ public static final String MESSAGE_PRIORITIZE_TASK_SUCCESS = "Prioritized task: %1$s";
+ public static final String MESSAGE_DUPLICATE_TAG = "This tag already exists in the tag list";
+ public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
+ public static final String MESSAGE_TAG_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_NULL_TIMING =
+ "Both the start and end timings must be specified for a recurring task";
+
+ public final int targetIndex;
+ public final EditTaskDescriptor prioritizeTaskDescriptor;
+
+ public PrioritizeCommand(int targetIndex, Priority newPriority) {
+ assert targetIndex > 0;
+
+ this.targetIndex = targetIndex - 1;
+ this.prioritizeTaskDescriptor = new EditTaskDescriptor();
+ this.prioritizeTaskDescriptor.setPriority(Optional.of(newPriority));
+ }
+
+ @Override
+ public CommandResult execute() throws CommandException {
+
+ UnmodifiableObservableList lastShownList = model.getFilteredTaskList();
+ if (lastShownList.size() <= targetIndex) {
+ logger.info(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
+ }
+
+ ReadOnlyTask taskToComplete = lastShownList.get(targetIndex);
+ Task completedTask = createPrioritizedTask(taskToComplete, prioritizeTaskDescriptor);
+
+ try {
+ model.updateTask(targetIndex, completedTask);
+ } catch (UniqueTaskList.DuplicateTaskException dpe) {
+ logger.info(MESSAGE_DUPLICATE_TASK);
+ throw new CommandException(MESSAGE_DUPLICATE_TASK);
+ }
+
+ model.updateFilteredListToShowAll();
+ logger.info(String.format(MESSAGE_PRIORITIZE_TASK_SUCCESS, taskToComplete));
+ return new CommandResult(String.format(MESSAGE_PRIORITIZE_TASK_SUCCESS, taskToComplete));
+ }
+
+ /**
+ * Creates and returns a {@code Task} with the details of {@code taskToComplete}
+ * edited with {@code editTaskDescriptor}.
+ */
+ private static Task createPrioritizedTask(ReadOnlyTask taskToPrioritize,
+ EditTaskDescriptor editTaskDescriptor) throws CommandException {
+ assert taskToPrioritize != null;
+
+ Description updatedDescription = editTaskDescriptor.getDescription()
+ .orElseGet(taskToPrioritize::getDescription);
+ Priority updatedPriority = editTaskDescriptor.getPriority().orElseGet(taskToPrioritize::getPriority);
+ Timing updatedStartDate = editTaskDescriptor.getStartTiming().orElseGet(taskToPrioritize::getStartTiming);
+ Timing updatedEndDate = editTaskDescriptor.getEndTiming().orElseGet(taskToPrioritize::getEndTiming);
+ UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToPrioritize::getTags);
+ boolean updatedRecurring = editTaskDescriptor.isRecurring().orElseGet(taskToPrioritize::isRecurring);
+ RecurringFrequency updatedFrequency = editTaskDescriptor.getFrequency()
+ .orElseGet(taskToPrioritize::getFrequency);
+
+ try {
+ return new Task(updatedDescription, updatedPriority, updatedStartDate,
+ updatedEndDate, updatedTags, updatedRecurring, updatedFrequency);
+ } catch (IllegalValueException e) {
+ throw new CommandException(MESSAGE_NULL_TIMING);
+ }
+ }
+}
diff --git a/src/main/java/seedu/task/logic/commands/RedoCommand.java b/src/main/java/seedu/task/logic/commands/RedoCommand.java
new file mode 100644
index 000000000000..e48babb3e2ef
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/RedoCommand.java
@@ -0,0 +1,31 @@
+//@@author A0113795Y
+package seedu.task.logic.commands;
+
+import java.util.EmptyStackException;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.logic.commands.exceptions.CommandException;
+
+/**
+ * Redo the previous change undone to the Task Manager
+ */
+public class RedoCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(RedoCommand.class);
+ public static final String COMMAND_WORD = "redo";
+ public static final String MESSAGE_SUCCESS = "Preivous undo restored.";
+ public static final String MESSAGE_INVALID_REDO_COMMAND = "Nothing to redo!";
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ try {
+ model.redo();
+ } catch (EmptyStackException ese) {
+ logger.info(MESSAGE_INVALID_REDO_COMMAND);
+ throw new CommandException(MESSAGE_INVALID_REDO_COMMAND);
+ }
+ logger.info(MESSAGE_SUCCESS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/task/logic/commands/SaveCommand.java b/src/main/java/seedu/task/logic/commands/SaveCommand.java
new file mode 100644
index 000000000000..c2932fc8d312
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/SaveCommand.java
@@ -0,0 +1,93 @@
+//@@author A0163559U
+package seedu.task.logic.commands;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.Config;
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.ConfigUtil;
+import seedu.task.commons.util.FileUtil;
+import seedu.task.logic.commands.exceptions.CommandException;
+
+/**
+ * Saves task data in the specified directory and updates the default save directory.
+ */
+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_USAGE = COMMAND_WORD
+ + ": Saves all tasks in specified directory with specified file name. "
+ + "Parameters: SAVE_LOCATION\n"
+ + "Example: " + COMMAND_WORD
+ + " /Users/username/Documents/TaskManager/taskmanager.xml";
+
+ public static final String MESSAGE_SUCCESS = "Tasks saved in location: %1$s";
+ public static final String MESSAGE_INVALID_SAVE_LOCATION = "This save location is invalid: %1$s";
+ public static final String MESSAGE_NULL_SAVE_LOCATION = "A save location must be specified.\n" +
+ "Otherwise, saving occurs automatically in the current save location.";
+ public static final String MESSAGE_DIRECTORY_SAVE_LOCATION = "A save location must also include the file name.";
+ public static final String MESSAGE_SAVE_IO_EXCEPTION = "Failed to save file in location: %1$s";
+
+ private final File toSave;
+ /**
+ * Creates an SaveCommand using raw values.
+ *
+ * @throws IllegalValueException if the save location is invalid
+ * @throws IOException
+ */
+ public SaveCommand(String fileAsString) throws IllegalValueException {
+ if (fileAsString == null || fileAsString.equals("")) {
+ throw new IllegalValueException(MESSAGE_NULL_SAVE_LOCATION);
+ }
+ this.toSave = new File(fileAsString.trim());
+ if (toSave.isDirectory()) {
+ throw new IllegalValueException(MESSAGE_DIRECTORY_SAVE_LOCATION);
+ }
+ try {
+ createSaveFile();
+ } catch (IOException ioe) {
+ throw new IllegalValueException(String.format(MESSAGE_INVALID_SAVE_LOCATION, fileAsString));
+ }
+ assert toSave.exists();
+
+ }
+
+ private boolean createSaveFile() throws IOException {
+ boolean created = FileUtil.createFile(toSave);
+ if (!FileUtil.isFileExists(toSave) && !created) {
+ throw new IOException();
+ }
+ return created;
+ }
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ assert config != null;
+ logger.info("Executing load command with " + toSave.toString());
+
+ try {
+
+ storage.saveTaskListInNewLocation(model.getTaskList(), toSave);
+
+ //update configuration to reflect new save location
+ config.setTaskManagerFilePath(toSave.toString());
+
+ ConfigUtil.saveConfig(config, Config.DEFAULT_CONFIG_FILE);
+
+ } catch (IOException e) {
+ logger.warning("Failed to execute save.");
+
+ throw new CommandException(String.format(MESSAGE_SAVE_IO_EXCEPTION, toSave.toString()));
+ }
+ logger.info("Execute save succeeded");
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toSave.toString()));
+
+ }
+
+}
diff --git a/src/main/java/seedu/task/logic/commands/UndoCommand.java b/src/main/java/seedu/task/logic/commands/UndoCommand.java
new file mode 100644
index 000000000000..5ad25d23d5ef
--- /dev/null
+++ b/src/main/java/seedu/task/logic/commands/UndoCommand.java
@@ -0,0 +1,31 @@
+//@@author A0113795Y
+package seedu.task.logic.commands;
+
+import java.util.EmptyStackException;
+import java.util.logging.Logger;
+
+import seedu.task.commons.core.LogsCenter;
+import seedu.task.logic.commands.exceptions.CommandException;
+
+/**
+ * Undo the previous change to the Task Manager
+ */
+public class UndoCommand extends Command {
+ private static final Logger logger = LogsCenter.getLogger(UndoCommand.class);
+ public static final String COMMAND_WORD = "undo";
+ public static final String MESSAGE_SUCCESS = "Previous change is undone";
+ public static final String MESSAGE_INVALID_UNDO_COMMAND = "Nothing to undo!";
+
+ @Override
+ public CommandResult execute() throws CommandException {
+ assert model != null;
+ try {
+ model.undo();
+ } catch (EmptyStackException ese) {
+ logger.info(MESSAGE_INVALID_UNDO_COMMAND);
+ throw new CommandException(MESSAGE_INVALID_UNDO_COMMAND);
+ }
+ logger.info(MESSAGE_SUCCESS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/task/logic/commands/exceptions/CommandException.java
similarity index 81%
rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
rename to src/main/java/seedu/task/logic/commands/exceptions/CommandException.java
index ed23ad42eb26..f327c12f8549 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/task/logic/commands/exceptions/CommandException.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands.exceptions;
+package seedu.task.logic.commands.exceptions;
/**
* Represents an error which occurs during execution of a {@link Command}.
diff --git a/src/main/java/seedu/task/logic/parser/AddCommandParser.java b/src/main/java/seedu/task/logic/parser/AddCommandParser.java
new file mode 100644
index 000000000000..1f64864f9f00
--- /dev/null
+++ b/src/main/java/seedu/task/logic/parser/AddCommandParser.java
@@ -0,0 +1,77 @@
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.task.commons.core.Messages.MESSSAGE_INVALID_TIMING_ORDER;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_PRIORITY;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_RECURRING;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_START_DATE;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.NoSuchElementException;
+
+import seedu.task.commons.exceptions.IllegalTimingOrderException;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.AddCommand;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.IncorrectCommand;
+
+/**
+ * Parses input arguments and creates a new AddCommand object
+ */
+public class AddCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddCommand
+ * and returns an AddCommand object for execution.
+ */
+ public Command parse(String args) {
+ ArgumentTokenizer argsTokenizer =
+ new ArgumentTokenizer(PREFIX_PRIORITY, PREFIX_START_DATE,
+ PREFIX_END_DATE, PREFIX_TAG, PREFIX_RECURRING);
+ argsTokenizer.tokenize(args);
+ String priority;
+ String startDate;
+ String endDate;
+ String recur;
+
+ try {
+ priority = argsTokenizer.getValue(PREFIX_PRIORITY).get();
+ } catch (NoSuchElementException e) {
+ priority = null;
+ }
+
+ try {
+ startDate = argsTokenizer.getValue(PREFIX_START_DATE).get();
+ } catch (NoSuchElementException e) {
+ startDate = null;
+ }
+
+ try {
+ endDate = argsTokenizer.getValue(PREFIX_END_DATE).get();
+ } catch (NoSuchElementException e) {
+ endDate = null;
+ }
+
+ try {
+ recur = argsTokenizer.getValue(PREFIX_RECURRING).get();
+ } catch (NoSuchElementException e) {
+ recur = null;
+ }
+
+ try {
+ return new AddCommand(
+ argsTokenizer.getPreamble().get(),
+ priority, startDate, endDate, recur,
+ ParserUtil.toSet(argsTokenizer.getAllValues(PREFIX_TAG))
+ );
+ } catch (NoSuchElementException nsee) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(ive.getMessage());
+ } catch (IllegalTimingOrderException itoe) {
+ return new IncorrectCommand(MESSSAGE_INVALID_TIMING_ORDER);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/task/logic/parser/ArgumentTokenizer.java
similarity index 99%
rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
rename to src/main/java/seedu/task/logic/parser/ArgumentTokenizer.java
index 0414b85cbc66..3e97c04254d1 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/task/logic/parser/ArgumentTokenizer.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.task.logic.parser;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/task/logic/parser/CliSyntax.java
similarity index 55%
rename from src/main/java/seedu/address/logic/parser/CliSyntax.java
rename to src/main/java/seedu/task/logic/parser/CliSyntax.java
index b8d15669f41a..e1b3dbef9033 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/task/logic/parser/CliSyntax.java
@@ -1,8 +1,8 @@
-package seedu.address.logic.parser;
+package seedu.task.logic.parser;
import java.util.regex.Pattern;
-import seedu.address.logic.parser.ArgumentTokenizer.Prefix;
+import seedu.task.logic.parser.ArgumentTokenizer.Prefix;
/**
* Contains Command Line Interface (CLI) syntax definitions common to multiple commands
@@ -10,10 +10,12 @@
public class CliSyntax {
/* Prefix definitions */
- public static final Prefix PREFIX_PHONE = new Prefix("p/");
- public static final Prefix PREFIX_EMAIL = new Prefix("e/");
- public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
+ public static final Prefix PREFIX_PRIORITY = new Prefix("p/");
+ public static final Prefix PREFIX_START_DATE = new Prefix("sd/");
+ public static final Prefix PREFIX_END_DATE = new Prefix("ed/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_RECURRING = new Prefix("r/");
+
/* Patterns definitions */
public static final Pattern KEYWORDS_ARGS_FORMAT =
diff --git a/src/main/java/seedu/task/logic/parser/CompleteCommandParser.java b/src/main/java/seedu/task/logic/parser/CompleteCommandParser.java
new file mode 100644
index 000000000000..d0bb93c85309
--- /dev/null
+++ b/src/main/java/seedu/task/logic/parser/CompleteCommandParser.java
@@ -0,0 +1,30 @@
+//@@author A0113795Y
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Optional;
+
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.CompleteCommand;
+import seedu.task.logic.commands.IncorrectCommand;
+
+/**
+ * Parses input arguments and creates a new DeleteCommand object
+ */
+public class CompleteCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteCommand
+ * and returns an DeleteCommand object for execution.
+ */
+ public Command parse(String args) {
+
+ Optional index = ParserUtil.parseIndex(args);
+ if (!index.isPresent()) {
+ return new IncorrectCommand(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, CompleteCommand.MESSAGE_USAGE));
+ }
+ return new CompleteCommand(index.get());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/task/logic/parser/DeleteCommandParser.java
similarity index 60%
rename from src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
rename to src/main/java/seedu/task/logic/parser/DeleteCommandParser.java
index 313252b20f75..6ba8c1e3c9b9 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/task/logic/parser/DeleteCommandParser.java
@@ -1,12 +1,12 @@
-package seedu.address.logic.parser;
+package seedu.task.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import java.util.Optional;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.DeleteCommand;
+import seedu.task.logic.commands.IncorrectCommand;
/**
* Parses input arguments and creates a new DeleteCommand object
@@ -17,7 +17,7 @@ public class DeleteCommandParser {
* Parses the given {@code String} of arguments in the context of the DeleteCommand
* and returns an DeleteCommand object for execution.
*/
- public Command parse(String args) {
+ public Command parse(String args, boolean isSpecific) {
Optional index = ParserUtil.parseIndex(args);
if (!index.isPresent()) {
@@ -25,7 +25,7 @@ public Command parse(String args) {
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
}
- return new DeleteCommand(index.get());
+ return new DeleteCommand(index.get(), isSpecific);
}
}
diff --git a/src/main/java/seedu/task/logic/parser/EditCommandParser.java b/src/main/java/seedu/task/logic/parser/EditCommandParser.java
new file mode 100644
index 000000000000..a89ef89d2ab2
--- /dev/null
+++ b/src/main/java/seedu/task/logic/parser/EditCommandParser.java
@@ -0,0 +1,78 @@
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_PRIORITY;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_RECURRING;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_START_DATE;
+import static seedu.task.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.EditCommand;
+import seedu.task.logic.commands.IncorrectCommand;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.EditTaskDescriptor;
+
+/**
+ * Parses input arguments and creates a new EditCommand object
+ */
+public class EditCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditCommand
+ * and returns an EditCommand object for execution.
+ */
+ public Command parse(String args, boolean isSpecific) {
+ assert args != null;
+ ArgumentTokenizer argsTokenizer =
+ new ArgumentTokenizer(PREFIX_PRIORITY, PREFIX_START_DATE,
+ PREFIX_END_DATE, PREFIX_TAG, PREFIX_RECURRING);
+ argsTokenizer.tokenize(args);
+ List> preambleFields = ParserUtil.splitPreamble(argsTokenizer.getPreamble().orElse(""), 2);
+
+ Optional index = preambleFields.get(0).flatMap(ParserUtil::parseIndex);
+ if (!index.isPresent()) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE));
+ }
+
+ EditTaskDescriptor editTaskDescriptor = new EditTaskDescriptor();
+ try {
+ editTaskDescriptor.setDescription(ParserUtil.parseDescription(preambleFields.get(1)));
+ editTaskDescriptor.setPriority(ParserUtil.parsePriority(argsTokenizer.getValue(PREFIX_PRIORITY)));
+ editTaskDescriptor.setStartTiming(ParserUtil.parseTiming(argsTokenizer.getValue(PREFIX_START_DATE)));
+ editTaskDescriptor.setEndTiming(ParserUtil.parseTiming(argsTokenizer.getValue(PREFIX_END_DATE)));
+ editTaskDescriptor.setTags(parseTagsForEdit(ParserUtil.toSet(argsTokenizer.getAllValues(PREFIX_TAG))));
+ editTaskDescriptor.setFrequency(ParserUtil.parseFrequency(argsTokenizer.getValue(PREFIX_RECURRING)));
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(ive.getMessage());
+ }
+
+ if (!editTaskDescriptor.isAnyFieldEdited()) {
+ return new IncorrectCommand(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditCommand(index.get(), editTaskDescriptor, isSpecific);
+ }
+
+ /**
+ * Parses {@code Collection tags} into an {@code Optional} if {@code tags} is non-empty.
+ * If {@code tags} contain only one element which is an empty string, it will be parsed into a
+ * {@code Optional} containing zero tags.
+ */
+ private Optional parseTagsForEdit(Collection tags) throws IllegalValueException {
+ assert tags != null;
+
+ if (tags.isEmpty()) {
+ return Optional.empty();
+ }
+ Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
+ return Optional.of(ParserUtil.parseTags(tagSet));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/task/logic/parser/FindCommandParser.java
similarity index 73%
rename from src/main/java/seedu/address/logic/parser/FindCommandParser.java
rename to src/main/java/seedu/task/logic/parser/FindCommandParser.java
index 1cac3916409e..3c4af896fcef 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/task/logic/parser/FindCommandParser.java
@@ -1,16 +1,16 @@
-package seedu.address.logic.parser;
+package seedu.task.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.KEYWORDS_ARGS_FORMAT;
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.task.logic.parser.CliSyntax.KEYWORDS_ARGS_FORMAT;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.FindCommand;
+import seedu.task.logic.commands.IncorrectCommand;
/**
* Parses input arguments and creates a new FindCommand object
diff --git a/src/main/java/seedu/task/logic/parser/LoadCommandParser.java b/src/main/java/seedu/task/logic/parser/LoadCommandParser.java
new file mode 100644
index 000000000000..eb91045a5b63
--- /dev/null
+++ b/src/main/java/seedu/task/logic/parser/LoadCommandParser.java
@@ -0,0 +1,37 @@
+//@@author A0163559U
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.NoSuchElementException;
+
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.LoadCommand;
+
+/**
+ * Parses input arguments and creates a new LoadCommand object
+ */
+public class LoadCommandParser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the LoadCommand
+ * and returns a LoadCommand object for execution.
+ */
+ public Command parse(String args) {
+ if (args == null || args.trim().equals("")) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, LoadCommand.MESSAGE_USAGE));
+ }
+ String trimmedArgs = args.trim();
+ try {
+ //System.out.println("@@@Parsing load command: " + args);
+ return new LoadCommand(trimmedArgs);
+ } catch (NoSuchElementException nsee) {
+ return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, LoadCommand.MESSAGE_USAGE));
+ } catch (IllegalValueException ive) {
+ return new IncorrectCommand(ive.getMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/task/logic/parser/Parser.java b/src/main/java/seedu/task/logic/parser/Parser.java
new file mode 100644
index 000000000000..4dda7ea78863
--- /dev/null
+++ b/src/main/java/seedu/task/logic/parser/Parser.java
@@ -0,0 +1,105 @@
+package seedu.task.logic.parser;
+
+import static seedu.task.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.task.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import seedu.task.logic.commands.AddCommand;
+import seedu.task.logic.commands.ClearCommand;
+import seedu.task.logic.commands.Command;
+import seedu.task.logic.commands.CompleteCommand;
+import seedu.task.logic.commands.DeleteCommand;
+import seedu.task.logic.commands.EditCommand;
+import seedu.task.logic.commands.ExitCommand;
+import seedu.task.logic.commands.FindCommand;
+import seedu.task.logic.commands.HelpCommand;
+import seedu.task.logic.commands.IncorrectCommand;
+import seedu.task.logic.commands.ListCommand;
+import seedu.task.logic.commands.LoadCommand;
+import seedu.task.logic.commands.PrioritizeCommand;
+import seedu.task.logic.commands.RedoCommand;
+import seedu.task.logic.commands.SaveCommand;
+import seedu.task.logic.commands.UndoCommand;
+
+/**
+ * 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+)(?.*)");
+
+ /**
+ * 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 new AddCommandParser().parse(arguments);
+
+ case EditCommand.COMMAND_WORD:
+ return new EditCommandParser().parse(arguments, false);
+
+ case EditCommand.COMMAND_WORD_REC:
+ return new EditCommandParser().parse(arguments, true);
+
+ case DeleteCommand.COMMAND_WORD:
+ return new DeleteCommandParser().parse(arguments, false);
+
+ case DeleteCommand.COMMAND_WORD_REC:
+ return new DeleteCommandParser().parse(arguments, true);
+
+ case ClearCommand.COMMAND_WORD:
+ return new ClearCommand();
+
+ case FindCommand.COMMAND_WORD:
+ return new FindCommandParser().parse(arguments);
+
+ case ListCommand.COMMAND_WORD:
+ return new ListCommand();
+
+ case ExitCommand.COMMAND_WORD:
+ return new ExitCommand();
+
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
+
+ case CompleteCommand.COMMAND_WORD:
+ return new CompleteCommandParser().parse(arguments);
+
+ case PrioritizeCommand.COMMAND_WORD:
+ return new PrioritizeCommandParser().parse(arguments);
+
+ case UndoCommand.COMMAND_WORD:
+ return new UndoCommand();
+
+ case RedoCommand.COMMAND_WORD:
+ return new RedoCommand();
+
+ case SaveCommand.COMMAND_WORD:
+ return new SaveCommandParser().parse(arguments);
+
+ case LoadCommand.COMMAND_WORD:
+ return new LoadCommandParser().parse(arguments);
+
+ default:
+ return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/task/logic/parser/ParserUtil.java
similarity index 58%
rename from src/main/java/seedu/address/logic/parser/ParserUtil.java
rename to src/main/java/seedu/task/logic/parser/ParserUtil.java
index bf485e4f292d..f65c974ea148 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/task/logic/parser/ParserUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.task.logic.parser;
import java.util.Arrays;
import java.util.Collection;
@@ -11,14 +11,14 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.model.tag.UniqueTagList;
+import seedu.task.commons.exceptions.IllegalValueException;
+import seedu.task.commons.util.StringUtil;
+import seedu.task.model.tag.Tag;
+import seedu.task.model.tag.UniqueTagList;
+import seedu.task.model.task.Description;
+import seedu.task.model.task.Priority;
+import seedu.task.model.task.RecurringFrequency;
+import seedu.task.model.task.Timing;
/**
* Contains utility methods used for parsing strings in the various *Parser classes
@@ -56,10 +56,10 @@ public static Set toSet(Optional> list) {
}
/**
- * Splits a preamble string into ordered fields.
- * @return A list of size {@code numFields} where the ith element is the ith field value if specified in
- * the input, {@code Optional.empty()} otherwise.
- */
+ * Splits a preamble string into ordered fields.
+ * @return A list of size {@code numFields} where the ith element is the ith field value if specified in
+ * the input, {@code Optional.empty()} otherwise.
+ */
public static List> splitPreamble(String preamble, int numFields) {
return Arrays.stream(Arrays.copyOf(preamble.split("\\s+", numFields), numFields))
.map(Optional::ofNullable)
@@ -67,35 +67,27 @@ public static List> splitPreamble(String preamble, int numField
}
/**
- * Parses a {@code Optional name} into an {@code Optional} if {@code name} is present.
+ * Parses a {@code Optional