diff --git a/README.md b/README.md index 84755485a7..36829d8ad5 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ # Tutorials -Duke Increment | Tutorial +Duke.Duke Increment | Tutorial ---------------|--------------- `A-Gradle` | [Gradle Tutorial](tutorials/gradleTutorial.md) `A-TextUiTesting` | [Text UI Testing Tutorial](tutorials/textUiTestingTutorial.md) -`Level-10` | JavaFX tutorials:
→ [Part 1: Introduction to JavaFX][fx1]
→ [Part 2: Creating a GUI for Duke][fx2]
→ [Part 3: Interacting with the user][fx3]
→ [Part 4: Introduction to FXML][fx4] +`Level-10` | JavaFX tutorials:
→ [Part 1: Introduction to JavaFX][fx1]
→ [Part 2: Creating a GUI for Duke.Duke][fx2]
→ [Part 3: Interacting with the user][fx3]
→ [Part 4: Introduction to FXML][fx4] [fx1]: [fx2]: diff --git a/data.txt b/data.txt new file mode 100644 index 0000000000..225bdc1c1d --- /dev/null +++ b/data.txt @@ -0,0 +1,3 @@ +0|Career Fair|E|26-02-2020 +0|English Essay|D|26 Feb +0|CS2105 Assignment|D|next week diff --git a/docs/README.md b/docs/README.md index fd44069597..6e4a106009 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,20 +1,149 @@ -# User Guide +# Introduction -## Features +Duke is a command-line interface task manager. You can use Duke to manage a list of to-do items, upcoming deadlines, and upcoming events. The list is saved upon exit and will be loaded upon the next session of Duke. -### Feature 1 -Description of feature. +# Features -## Usage +This section describes the features that Duke supports. -### `Keyword` - Describe action +NOTE: +* Commands have to be the first word of the user input and in lower case +* Words in ```UPPER_CASE``` are the parameters to be supplied by the user -Describe action and its outcome. -Example of usage: +## 1. Adding New Tasks -`keyword (optional arguments)` +New tasks can be added by typing the command relevant to the type of task that is to be added (i.e. ```todo```,``` event``` or ```deadline```). -Expected outcome: +#### 1.1 Adding New To-Dos: ```todo``` +- Adds a new to-do item to the task list. +- Format: ```todo NAME_OF_TASK``` +- Examples: + - ```todo Math Online Quiz``` + - ```todo CS2113 Homework``` +- Expected Output: +``` +todo CS2113 Homework +____________________________________________________________ +Got it. I've added this task: +[T][X] CS2113 Homework +Now you have 2 tasks in the list. +____________________________________________________________ +``` -`outcome` +#### 1.2 Adding New Events: ```event``` +- Adds a new event to the task list. +- Format: ```event NAME_OF_EVENT /at DATE_OF_EVENT``` +- Examples: + - ```event Career Fair /at 26-02-2020``` + - ```event Family Gathering /at 26 Feb``` + - ```event Computing Convention /at Next Month``` +- Expected Output: +``` +event Career Fair /at 26-02-2020 +____________________________________________________________ +Got it. I've added this task: +[E][X] Career Fair (at: 26-02-2020) +Now you have 3 tasks in the list. +____________________________________________________________ +``` + +#### 1.3 Adding New Deadlines: ```deadline``` +- Adds a new deadline to the task list. +- Format: ```deadline NAME_OF_DEADLINE /by DATE_OF_DEADLINE``` +- Examples: + - ```deadline Math Online Quiz /by 26-02-2020``` + - ```deadline English Essay /by 26 Feb``` + - ```deadline CS2113 Homework /by Tomorrow``` +- Expected Output: +``` +deadline English Essay /by 26 Feb +____________________________________________________________ +Got it. I've added this task: +[D][X] English Essay (by: 26 Feb) +Now you have 4 tasks in the list. +____________________________________________________________ +``` + +## 2. Listing All Tasks: ```list``` +- Lists all task in the list. +- Format: ```list``` +- Expected Output: +``` +list +1.[T][O] CS2113 Homework +2.[E][X] Career Fair (at: 26-02-2020) +3.[D][X] English Essay (by: 26 Feb) +``` + +## 3. Finding Tasks by Keyword: ```find``` +- Lists all task in the list that contains the specified keyword. +- Format: ```find KEYWORD``` +- Examples: + - ```find Math``` + - ```find CS2113``` + - ```find CS``` + +- Expected Output: +``` +find CS +____________________________________________________________ +Here are the matching tasks in your list: + +1.[T][X] CS2113 Homework +2.[D][X] CS2105 Assignment (by: next week) +____________________________________________________________ +``` + +## 4. Marking Tasks as Done: ```done``` +- Marks specified tasks as done. +- Specified index of the task will be its index of the entire task list by default, unless the ```list``` or ```find``` command has been called. In which case, it will be the index of the item as shown in the last shown list. +- Format: ```done INDEX``` +- Examples: + - ```done 1``` + - ```done 2``` +- Expected Output: +``` +done 1 +Nice! I've marked this task as done: +[O] CS2113 Homework +``` + +## 5. Deleting Tasks: ```delete``` +- Delete specified tasks from the list. +- Specified index of the task will be its index of the entire task list by default, unless the ```list``` or ```find``` command has been called. In which case, it will be the index of the item as shown in the last shown list. +- Format: ```done INDEX``` +- Examples: + - ```delete 1``` + - ```delete 2``` +- Expected Output: +``` +delete 1 +____________________________________________________________ +Noted. I've removed this task: +[T][O] CS2113 Homework +Now you have 3 tasks in the list. +____________________________________________________________ + +``` + +## 6. Loading Tasks from File +- Loading of tasks will be done automatically upon starting the application when there is a saved file present in the same directory of the Duke application. The file has the name ```data.txt```. +- Expected Output: +``` +Previous tasks has been loaded successfully: +____________________________________________________________ +1.[E][X] Career Fair (at: 26-02-2020) +2.[D][X] English Essay (by: 26 Feb) +3.[D][X] CS2105 Assignment (by: next week) +``` + +## 7. Saving Tasks: ```bye``` +- Saving the state of the task list is done automatically when the program is exited using the ```bye`` command. +- Format: ```bye``` +- Expected Output: + +``` +bye +Bye. Hope to see you again soon! +``` diff --git a/saved/data.txt b/saved/data.txt new file mode 100644 index 0000000000..d9496d9c8d --- /dev/null +++ b/saved/data.txt @@ -0,0 +1,3 @@ +1|something|T +0|some date|D|tmr +0|some lame thing|E|ytd diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334cc..0000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/Duke/Deadline.java b/src/main/java/Duke/Deadline.java new file mode 100644 index 0000000000..c1b85f931e --- /dev/null +++ b/src/main/java/Duke/Deadline.java @@ -0,0 +1,48 @@ +package Duke; + +/** + * Represents a deadline object which is a task with a deadline date associated with it. + */ +public class Deadline extends Task { + protected String by; + + /** + * Constructor for a new deadline. + * @param description description for the deadline + * @param by the date for the deadline + */ + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + /** + * Constructor for deadlines that are read from a storage file. + * @param description description of the deadline + * @param by date of the deadline + * @param status status of the deadline + */ + public Deadline(String description, String by, String status) { + super(description); + this.by = by; + if (status.equals("1")) { + this.markAsDone(); + } + } + + /** + * @return a string containing the status, description and date of the deadline for printing + */ + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + this.by + ")"; + } + + /** + * @return a string of information of the deadline in the format for saving to a file + */ + @Override + public String toSaveFormat() { + return(super.toSaveFormat() + "D|" + this.by); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Duke.java b/src/main/java/Duke/Duke.java new file mode 100644 index 0000000000..c0454c9878 --- /dev/null +++ b/src/main/java/Duke/Duke.java @@ -0,0 +1,43 @@ +package Duke; + +import java.util.Scanner; +import java.util.ArrayList; +import java.io.File; +import java.io.FileNotFoundException; + +/** + * Represents the Duke task manager. + */ +public class Duke { + + public static final String GREETING = + "\n" + + " ___ _ \n" + + " | \\ _ _| |_____ \n" + + " | |) | || | / / -_)\n" + + " |___/ \\_,_|_\\_\\___|\n" + + " \n" + + "Hello! I'm Duke\n" + "What can I do for you?\n" + + "____________________________________________________________\n"; + public static final String GOODBYE = "Bye. Hope to see you again soon!"; + public static final String FILEPATH = "data.txt"; + + public static void main(String[] args) { + System.out.println(GREETING); + + File f = new File(FILEPATH); + + TaskList taskArray = new TaskList(); + + try { + Storage.loadFileContents(FILEPATH, taskArray); + Ui.printTasks(taskArray); + } catch (FileNotFoundException e) { + System.out.println("No saved file available"); + } + + Scanner scanner = new Scanner(System.in); + + Parser.parseUserCommands(taskArray, scanner); + } +} diff --git a/src/main/java/Duke/DukeException.java b/src/main/java/Duke/DukeException.java new file mode 100644 index 0000000000..c05991f530 --- /dev/null +++ b/src/main/java/Duke/DukeException.java @@ -0,0 +1,4 @@ +package Duke; + +public class DukeException extends Exception { +} diff --git a/src/main/java/Duke/Event.java b/src/main/java/Duke/Event.java new file mode 100644 index 0000000000..6424ef8f4a --- /dev/null +++ b/src/main/java/Duke/Event.java @@ -0,0 +1,48 @@ +package Duke; + +/** + * Represents an event-based task happening at a specific date. + */ +public class Event extends Task { + protected String at; + + /** + * Constructor for a new event. + * @param description description for the event + * @param at date of the event + */ + public Event(String description, String at) { + super(description); + this.at = at; + } + + /** + * Constructor for an event that is read from a storage file. + * @param description description of the event + * @param at date of the event + * @param status status of the event + */ + public Event(String description, String at, String status) { + super(description); + this.at = at; + if (status.equals("1")) { + this.markAsDone(); + } + } + + /** + * @return a string containing the status, description and date of the event for printing + */ + @Override + public String toString() { + return "[E]" + super.toString() + " (at: " + this.at + ")"; + } + + /** + * @return a string of information of the event in the format for saving to a file + */ + @Override + public String toSaveFormat() { + return(super.toSaveFormat() + "E|" + this.at); + } +} diff --git a/src/main/java/Duke/Parser.java b/src/main/java/Duke/Parser.java new file mode 100644 index 0000000000..643d25afb3 --- /dev/null +++ b/src/main/java/Duke/Parser.java @@ -0,0 +1,157 @@ +package Duke; + +import java.util.ArrayList; +import java.util.Scanner; + +/** + * Represents the object which parses user input to relevant functions for the execution of commands. + */ +public class Parser { + + /** + * Parses user commands to relevant functions to complete it while checking for user input errors. + * @param taskArray the task list of the current session to be parsed to relevant command methods + * @param scanner a scanner object that takes in user input + */ + public static void parseUserCommands(TaskList taskArray, Scanner scanner) { + ArrayList lastShownList = (ArrayList) taskArray.tasks.clone(); + boolean exit = false; + while (exit == false) { + String userInput = scanner.nextLine(); + String[] tokenizedInputs = userInput.split(" ", 2); + String instruction = tokenizedInputs[0]; + + switch (instruction) { + case "bye": + System.out.println(Duke.GOODBYE); + exit = true; + Storage.saveTasks(Duke.FILEPATH, taskArray); + break; + case "find": + if (isDescriptionEmpty(tokenizedInputs, instruction)) break; + String keyword = tokenizedInputs[1]; + lastShownList.clear(); + Ui.displayMatchingTasks(taskArray, lastShownList, keyword); + break; + case "list": + Ui.printTasks(taskArray); + lastShownList.clear(); + lastShownList = (ArrayList) taskArray.tasks.clone(); + break; + case "done": + if (isDescriptionEmpty(tokenizedInputs, instruction)) break; + int taskDone = 0; + try { + taskDone = Integer.valueOf(tokenizedInputs[1]) - 1; + } catch (Exception e){ + System.out.println("Sorry, invalid index entered.\n"); + break; + } + if (isOutOfBounds(lastShownList, taskDone)) break; + if (isInvalidTask(taskArray, lastShownList.get(taskDone))) break; + System.out.println("Nice! I've marked this task as done: "); + System.out.println(lastShownList.get(taskDone).markAsDone()); + break; + case "delete": + if (isDescriptionEmpty(tokenizedInputs, instruction)) break; + int taskToDelete = 0; + try { + taskToDelete = Integer.valueOf(tokenizedInputs[1]) - 1; + } catch (Exception e){ + System.out.println("Sorry, invalid index entered.\n"); + break; + } + if (isOutOfBounds(lastShownList, taskToDelete)) break; + if (isInvalidTask(taskArray, lastShownList.get(taskToDelete))) break; + Ui.respondDeleteSuccess(taskArray.size-1, lastShownList.get(taskToDelete)); + taskArray.deleteTask(lastShownList.get(taskToDelete)); + break; + case "todo": + if (isDescriptionEmpty(tokenizedInputs, instruction)) break; + taskArray.addTask(new ToDo(tokenizedInputs[1])); + Ui.respondAddedSuccess(taskArray.size, taskArray.get(taskArray.size-1)); + break; + case "deadline": + if (isDescriptionEmpty(tokenizedInputs, instruction)) break; + String[] deadlineInfo = tokenizedInputs[1].split(" /by "); + if (isDateEmpty(deadlineInfo)) break; + taskArray.addTask(new Deadline(deadlineInfo[0], deadlineInfo[1])); + Ui.respondAddedSuccess(taskArray.size, taskArray.get(taskArray.size-1)); + break; + case "event": + if (isDescriptionEmpty(tokenizedInputs, instruction)) break; + String[] eventInfo = tokenizedInputs[1].split(" /at "); + if (isDateEmpty(eventInfo)) break; + taskArray.addTask(new Event(eventInfo[0], eventInfo[1])); + Ui.respondAddedSuccess(taskArray.size, taskArray.get(taskArray.size-1)); + break; + default: + System.out.println("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + break; + } + } + } + + /** + * Checks if index supplied is out of bounds. + * @param lastShownList the last shown list from 'list' or 'find' commands. + * @param index the index supplied by user input from 'delete' or 'done' commands + * @return true if out of bounds and false if it is within bounds. + */ + private static boolean isOutOfBounds(ArrayList lastShownList, int index) { + if (index >= lastShownList.size()) { + System.out.println("Sorry, the task does not exist. Please use the 'list' or 'find' command for an updated list of tasks.\n"); + return true; + } + + if (index < 0) { + System.out.println("Sorry, invalid index entered.\n"); + return true; + } + return false; + } + + /** + * Checks if the task to be marked as done or deleted still exists as the last shown list may not be the most updated. + * For example, the user may have deleted and added new tasks since the last time the list or find command was called. + * @param taskArray the task array to check if it contains the chosen task extracted from the last shown list. + * @param requestedTask the task from the last shown list chosen by referencing its index + * @return true if the task is no longer valid and false if it is valid + */ + public static boolean isInvalidTask(TaskList taskArray, Task requestedTask) { + if (taskArray.taskExists(requestedTask) == false) { + System.out.println("Sorry the task no longer exists. Please use 'list' or 'find' for an updated list\n"); + return true; + } + return false; + } + + /** + * Checks if a date has been entered for new Events and Deadlines. + * @param information the information portion of the user input, further split into the description and date + * portions. + * @return true if the date portion is empty and false if the date portion is valid + */ + static boolean isDateEmpty(String[] information) { + if (information.length == 1) { + System.out.println("☹ OOPS!!! You did not enter a date"); + return true; + } + return false; + } + + /** + * Checks if the description portion of a command is empty. + * + * @param tokens an array containing the user input tokenized into the instruction and the task information + * @param instruction the instruction requested + * @return true if the description is empty and false if it is not empty + */ + static boolean isDescriptionEmpty(String[] tokens, String instruction) { + if (tokens.length == 1) { + System.out.println("☹ OOPS!!! The description of a " + instruction + " cannot be empty."); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Storage.java b/src/main/java/Duke/Storage.java new file mode 100644 index 0000000000..6fdd1f8d67 --- /dev/null +++ b/src/main/java/Duke/Storage.java @@ -0,0 +1,101 @@ +package Duke; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +/** + * Represents the interface between the application and the storage files. Provides methods to update and retrieve tasks + * from storage files. + */ +public class Storage { + /** + * Loads the task list for the current session with tasks located in a previously saved storage file. + * @param filePath the location of the storage file + * @param taskArray the task list to populate with tasks + * @throws FileNotFoundException + */ + public static void loadFileContents(String filePath, TaskList taskArray) throws FileNotFoundException { + File f = new File(filePath); + Scanner s = new Scanner(f); + int taskListSize = 0; + while (s.hasNext()) { + String newLine = s.nextLine(); + String[] tokenizedLine = newLine.split("\\|"); + String type = tokenizedLine[2]; + switch (type) { + case ("T"): + taskArray.addTask(new ToDo(tokenizedLine[1], tokenizedLine[0])); + break; + case ("E"): + taskArray.addTask(new Event(tokenizedLine[1], tokenizedLine[3], tokenizedLine[0])); + break; + case ("D"): + taskArray.addTask(new Deadline(tokenizedLine[1], tokenizedLine[3], tokenizedLine[0])); + break; + } + } + System.out.print("Previous tasks has been loaded successfully:\n" + + "____________________________________________________________\n"); + } + + /** + * Creates a new save file overwriting the existing one. + * + * @param filePath destination for the new storage file + * @param textToAdd the pre-formatted text string to be written to the file + * @throws IOException + */ + static void writeToFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(textToAdd); + fw.close(); + } + + /** + * Appends task to a pre-existing storage file without overwriting. + * + * @param filePath file of the existing save file to be appended to + * @param textToAppend the pre-formatted text string to append to the file + * @throws IOException + */ + static void appendToFile(String filePath, String textToAppend) throws IOException { + FileWriter fw = new FileWriter(filePath, true); // create a FileWriter in append mode + fw.write(textToAppend); + fw.close(); + } + + /** + * Saves the current state of the task list to a storage file. + * + * @param filePath the destination file path where the file will be stored + * @param taskArray the list of tasks to be saved in the file + * @see Storage#writeToFile(String, String) writeToFile + * @see Storage#appendToFile(String, String) appendToFile + * @see ToDo#toSaveFormat() ToDo + * @see Deadline#toSaveFormat() Deadline + * @see Event#toSaveFormat() Event + */ + public static void saveTasks(String filePath, TaskList taskArray) { + boolean overWrite = true; + for (Task currTask : taskArray.tasks) { + if(overWrite == true) { + try { + Storage.writeToFile(filePath, currTask.toSaveFormat() + "\n"); + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + overWrite = false; + } else { + try { + Storage.appendToFile(filePath, currTask.toSaveFormat() + "\n"); + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage() + "\n"); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Task.java b/src/main/java/Duke/Task.java new file mode 100644 index 0000000000..ed60786e22 --- /dev/null +++ b/src/main/java/Duke/Task.java @@ -0,0 +1,47 @@ +package Duke; + +/** + * Represents a task object that the user can mark as done when completed. + */ +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + + public String getStatusIcon() { + return (isDone ? "O" : "X"); //return tick or X symbols + } + + /** + * Updates the status of a task to done. + * @return a response string showing the updated status icon of the task + */ + public String markAsDone () { + this.isDone = true; + return ("[" + this.getStatusIcon() + "] "+ this.description); + } + + /** + * @return a string containing the task status and description for printing + */ + public String toString() { + return ("["+ this.getStatusIcon() + "] " + this.description); + } + + /** + * @return a string of containing the task status and description for saving + */ + public String toSaveFormat() { + if (this.isDone == true) { + return ("1|" + this.description+ "|"); + } else { + return ("0|" + this.description + "|"); + } + } + +} \ No newline at end of file diff --git a/src/main/java/Duke/TaskList.java b/src/main/java/Duke/TaskList.java new file mode 100644 index 0000000000..58cd165eb7 --- /dev/null +++ b/src/main/java/Duke/TaskList.java @@ -0,0 +1,60 @@ +package Duke; + +import java.util.ArrayList; + +/** + * Represents the list of tasks (todos, events and deadlines) relevant to the current user session. + * Provides methods to add tasks, delete tasks and retrieve tasks in the list. + */ +public class TaskList { + ArrayList tasks; + int size; + + /** + * Constructor for a new task array for the session. + */ + public TaskList() { + this.tasks = new ArrayList<>(); + size = 0; + } + + /** + * Adds a new task to the task array. + * @param task the task object to be added to the array + */ + public void addTask (Task task) { + tasks.add(task); + size++; + } + + /** + * Deletes a task from the task array. + * @param task the task object to be deleted from the array + */ + public void deleteTask (Task task) { + tasks.remove(task); + size--; + } + + /** + * Provides the task located in index index of the array. + * @param index the index of the task being queried + * @return the task located at index index + */ + public Task get (int index) { + return tasks.get(index); + } + + /** + * Checks if a task exists in the list. + * @param task the task to check + * @return true if tasks exists in the list, false if it doesn't + */ + public boolean taskExists (Task task) { + if (tasks.contains(task) == true) { + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/Duke/ToDo.java b/src/main/java/Duke/ToDo.java new file mode 100644 index 0000000000..ade8aa41d7 --- /dev/null +++ b/src/main/java/Duke/ToDo.java @@ -0,0 +1,43 @@ +package Duke; + +/** + * Represents a task object with an item that needs to be done, but does not have a specific date to be completed by. + */ +public class ToDo extends Task { + + /** + * Constructor for a new todo item. + * @param description the description of the ToDo item + */ + public ToDo(String description) { + super(description); + } + + /** + * Constructor for a todo task when reading from a saved file. + * @param description description of the ToDo item + * @param status the status of the ToDO item + */ + public ToDo(String description, String status) { + super(description); + if (status.equals("1")) { + this.markAsDone(); + } + } + + /** + * @return a string containing the status and the description of the todo item for printing. + */ + @Override + public String toString() { + return ("[T]" + super.toString()); + } + + /** + * @return @return a string of information of the todo item in the format for saving to a file + */ + @Override + public String toSaveFormat() { + return(super.toSaveFormat() + "T"); + } +} diff --git a/src/main/java/Duke/Ui.java b/src/main/java/Duke/Ui.java new file mode 100644 index 0000000000..9721099673 --- /dev/null +++ b/src/main/java/Duke/Ui.java @@ -0,0 +1,98 @@ +package Duke; + +import java.util.ArrayList; + + +/** + * Represents the interface between the application and the user where messages are printed to the terminal. + */ +public class Ui { + + /** + * Displays a list of tasks that have descriptions which contain the keyword searched. + * @param taskArray the full task array to search + * @param lastShownList the last shown list to be overwritten when this function is called + * @param keyword the search term to be matched against task descriptions + * @see Ui#printFindResults(ArrayList, int) printFindResults + */ + public static void displayMatchingTasks(TaskList taskArray, ArrayList lastShownList, String keyword) { + int lastShownListSize = 0; + for (Task i : taskArray.tasks) { + if (i.description.contains(keyword)) { + lastShownList.add(i); + lastShownListSize++; + } + } + if (lastShownListSize > 0) { + System.out.println("____________________________________________________________\n" + + " Here are the matching tasks in your list:\n"); + Ui.printFindResults(lastShownList, lastShownListSize); + System.out.println("____________________________________________________________\n"); + } else { + System.out.println("There are no tasks matching that description.\n"); + } + + } + + /** + * Prints a messages to user to show the task is going to be deleted from the task array. + * @param taskListSize the size of the task array after deletion + * @param task the task to be deleted + */ + public static void respondDeleteSuccess(int taskListSize, Task task) { + + System.out.println("____________________________________________________________\n" + + "Noted. I've removed this task:\n" + task.toString()); + System.out.print("Now you have "); + System.out.print(taskListSize); + if (taskListSize == 1) { + System.out.print(" task in the list.\n" + + "____________________________________________________________\n"); + } else { + System.out.print(" tasks in the list.\n" + + "____________________________________________________________\n"); + } + } + + /** + * Prints a message to the user to show that the task has been added successfully to the task array. + * @param taskListSize the number of tasks in the array + * @param task the new task that was just added + */ + public static void respondAddedSuccess(int taskListSize, Task task) { + System.out.println("____________________________________________________________\n" + + "Got it. I've added this task:\n" + task.toString()); + System.out.print("Now you have "); + System.out.print(taskListSize); + if (taskListSize <= 0) { + System.out.print(" task in the list.\n" + + "____________________________________________________________"); + } else { + System.out.print(" tasks in the list.\n" + + "____________________________________________________________\n"); + } + } + + /** + * Prints all tasks in the task array. + * @param taskArray the full array of tasks + */ + public static void printTasks(TaskList taskArray) { + for (int i = 1; i <= taskArray.size; i++) { + System.out.print(i); + System.out.println("." + taskArray.get(i - 1).toString()); + } + } + + /** + * Prints the results from the {@link Ui#displayMatchingTasks(TaskList, ArrayList, String) displayMatchingTasks} method which provides a list of matching tasks to print. + * @param results a list of tasks matching the keyword queried + * @param size size of the list of results + */ + public static void printFindResults (ArrayList results, int size) { + for (int i = 1; i <= size; i++) { + System.out.print(i); + System.out.println("." + results.get(i - 1).toString()); + } + } +} \ No newline at end of file diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..5699c7418f --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Duke.Duke + diff --git a/tutorials/gradleTutorial.md b/tutorials/gradleTutorial.md index 08292b118d..f3142111e2 100644 --- a/tutorials/gradleTutorial.md +++ b/tutorials/gradleTutorial.md @@ -30,10 +30,10 @@ As a developer, you write a _build file_ that describes the project. A build fil git checkout master git merge gradle ``` -1. Open the `build.gradle` file in an editor. Update the following code block to point to the main class (i.e., the one containing the `main` method) of your application. The code below assumes your main class is `seedu.duke.Duke` +1. Open the `build.gradle` file in an editor. Update the following code block to point to the main class (i.e., the one containing the `main` method) of your application. The code below assumes your main class is `seedu.duke.Duke.Duke` ```groovy application { - mainClassName = "seedu.duke.Duke" + mainClassName = "seedu.duke.Duke.Duke" } ``` 1. To check if Gradle has been added to the project correctly, open a terminal window, navigate to the root directory of your project and run the command `gradlew run`. This should result in Gradle running the main method of your project. @@ -146,7 +146,7 @@ By convention, java tests belong in `src/test/java` folder. Create a new `test/j src ├─main │ └─java -│ └─seedu/duke/Duke.java +│ └─seedu/duke/Duke.Duke.java └─test └─java └─seedu/duke/DukeTest.java diff --git a/tutorials/javaFxTutorialPart1.md b/tutorials/javaFxTutorialPart1.md index 561daeca43..b90034895d 100644 --- a/tutorials/javaFxTutorialPart1.md +++ b/tutorials/javaFxTutorialPart1.md @@ -44,7 +44,7 @@ javafx { ## Writing your first program -As customary, let’s start off with a simple “Hello World” program. Modify your `Duke` class to extend `javafx.application.Application`. This requires you to override the `Application#start()` method and provide a concrete implementation. Notice that the method signature for `Application#start()` has a parameter `Stage`. This is the _primary stage_ that JavaFX provides. +As customary, let’s start off with a simple “Hello World” program. Modify your `Duke.Duke` class to extend `javafx.application.Application`. This requires you to override the `Application#start()` method and provide a concrete implementation. Notice that the method signature for `Application#start()` has a parameter `Stage`. This is the _primary stage_ that JavaFX provides. ```java import javafx.application.Application; @@ -52,7 +52,7 @@ import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.stage.Stage; -public class Duke extends Application { +public class Duke.Duke extends Application { // ... @@ -73,7 +73,7 @@ Next, we create another Java class, `Launcher`, as an entry point to our applica The `Launcher` class is reproduced below in its entirety. ```java -import javafx.application.Application; +import Duke.Duke;import javafx.application.Application; /** * A launcher class to workaround classpath issues. diff --git a/tutorials/javaFxTutorialPart2.md b/tutorials/javaFxTutorialPart2.md index f24a0cd6ad..5060722948 100644 --- a/tutorials/javaFxTutorialPart2.md +++ b/tutorials/javaFxTutorialPart2.md @@ -1,8 +1,8 @@ -# JavaFX Tutorial Part 2 - Creating a GUI for Duke +# JavaFX Tutorial Part 2 - Creating a GUI for Duke.Duke -In this tutorial, we will be creating a GUI for Duke from scratch based on the following mockup. +In this tutorial, we will be creating a GUI for Duke.Duke from scratch based on the following mockup. -![Mockup for Duke](assets/DukeMockup.png) +![Mockup for Duke.Duke](assets/DukeMockup.png) ## JavaFX controls @@ -34,7 +34,7 @@ But how do we get the exact layout we want in the UI? JavaFX provides that funct One way to obtain the layout in the mockup is as follows. -![Duke's layout](assets/DukeSceneGraph.png) +![Duke.Duke's layout](assets/DukeSceneGraph.png) To get that layout, we create a new `AnchorPane` and add our controls to it. Similarly, we create a new `VBox` to hold the contents of the `ScrollPane`. The code should look something like this: @@ -49,7 +49,7 @@ import javafx.scene.layout.VBox; import javafx.stage.Stage; -public class Duke extends Application { +public class Duke.Duke extends Application { private ScrollPane scrollPane; private VBox dialogContainer; @@ -88,7 +88,7 @@ public class Duke extends Application { Run the application and you should see something like this: -![Duke's raw layout](assets/RawLayout.png) +![Duke.Duke's raw layout](assets/RawLayout.png) That is not what we were expecting, what did we forget to do? @@ -106,7 +106,7 @@ Add the following code to the bottom of the `start` method. You'll have to add ` //... //Step 2. Formatting the window to look as expected - stage.setTitle("Duke"); + stage.setTitle("Duke.Duke"); stage.setResizable(false); stage.setMinHeight(600.0); stage.setMinWidth(400.0); @@ -141,7 +141,7 @@ Add the following code to the bottom of the `start` method. You'll have to add ` Run the application again. It should now look like this: -![Duke's Final layout](assets/FinalLayout.png) +![Duke.Duke's Final layout](assets/FinalLayout.png) ## Exercises diff --git a/tutorials/javaFxTutorialPart3.md b/tutorials/javaFxTutorialPart3.md index a9e1bdddd3..88c48326cd 100644 --- a/tutorials/javaFxTutorialPart3.md +++ b/tutorials/javaFxTutorialPart3.md @@ -8,7 +8,7 @@ Rather than to do everything in one try, let’s iterate and build up towards ou JavaFX has an _event-driven architecture style_. As such, we programmatically define _handler_ methods to execute as a response to certain _events_. When an event is detected, JavaFX will call the respective handlers. -For Duke, there are two events that we want to respond to, namely the user pressing `Enter` in the `TextField` and left-clicking the `Button`. These are the `onAction` event for the `TextField` and the `onMouseClicked` event for the `Button`. +For Duke.Duke, there are two events that we want to respond to, namely the user pressing `Enter` in the `TextField` and left-clicking the `Button`. These are the `onAction` event for the `TextField` and the `onMouseClicked` event for the `Button`. For now, let’s have the application add a new `Label` with the text from the `TextField`. Update the `Main` class as follows. You'll need to add an `import javafx.scene.control.Label;` too. ```java @@ -103,7 +103,7 @@ import javafx.scene.image.ImageView; ``` Next, add two images to the `main/resources/images` folder. -For this tutorial, we have two images `DaUser.png` and `DaDuke.png` to represent the user avatar and Duke's avatar respectively but you can use any image you want. +For this tutorial, we have two images `DaUser.png` and `DaDuke.png` to represent the user avatar and Duke.Duke's avatar respectively but you can use any image you want. Image|Filename ---|--- @@ -112,7 +112,7 @@ Image|Filename ```java -public class Duke extends Application { +public class Duke.Duke extends Application { // ... private Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png")); private Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); @@ -124,7 +124,7 @@ Add a new method to handle user input: ```java /** * Iteration 2: - * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * Creates two dialog boxes, one echoing user input and the other containing Duke.Duke's reply and then appends them to * the dialog container. Clears the user input after processing. */ private void handleUserInput() { @@ -142,7 +142,7 @@ private void handleUserInput() { * Replace this stub with your completed method. */ private String getResponse(String input) { - return "Duke heard: " + input; + return "Duke.Duke heard: " + input; } ``` @@ -170,7 +170,7 @@ Run the program and see how it works. ## Iteration 3 – Adding custom behavior to DialogBox -One additional benefit of defining a custom control is that we can add behavior specific to our `DialogBox`. Let’s add a method to flip a dialog box such that the image on the left to differentiate between user input and Duke’s output. +One additional benefit of defining a custom control is that we can add behavior specific to our `DialogBox`. Let’s add a method to flip a dialog box such that the image on the left to differentiate between user input and Duke.Duke’s output. ```java /** @@ -224,7 +224,7 @@ Run the application and play around with it. ![DialogBoxes Iteration 3](assets/DialogBoxesIteration3.png) Congratulations! -You have successfully implemented a fully functional GUI for Duke! +You have successfully implemented a fully functional GUI for Duke.Duke! ## Exercises diff --git a/tutorials/javaFxTutorialPart4.md b/tutorials/javaFxTutorialPart4.md index 0e0ab280c4..19258e8270 100644 --- a/tutorials/javaFxTutorialPart4.md +++ b/tutorials/javaFxTutorialPart4.md @@ -29,7 +29,7 @@ FXML is a XML-based language that allows us to define our user interface. Proper The FXML snippet define a TextField similar to the one that we programmatically defined previous in Tutorial 2. Notice how concise FXML is compared to the plain Java version. -Let's return to Duke and convert it to use FXML instead. +Let's return to Duke.Duke and convert it to use FXML instead. # Rebuilding the Scene using FXML @@ -101,14 +101,14 @@ We will get to that later. ## Using Controllers -As part of the effort to separate the code handling Duke's logic and UI, let's _refactor_ the UI-related code to its own class. +As part of the effort to separate the code handling Duke.Duke's logic and UI, let's _refactor_ the UI-related code to its own class. We call these UI classes _controllers_. Let's implement the `MainWindow` controller class that we specified in `MainWindow.fxml`. **MainWindow.java** ```java -import javafx.fxml.FXML; +import Duke;import Duke.Duke;import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ScrollPane; import javafx.scene.control.TextField; @@ -143,7 +143,7 @@ public class MainWindow extends AnchorPane { } /** - * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * Creates two dialog boxes, one echoing user input and the other containing Duke.Duke's reply and then appends them to * the dialog container. Clears the user input after processing. */ @FXML @@ -168,7 +168,7 @@ Similarly, methods like private methods like `handleUserInput` can be used in FX ## Using FXML in our application -Let's create a new `Main` class as the bridge between the existing logic in `Duke` and the UI in `MainWindow`. +Let's create a new `Main` class as the bridge between the existing logic in `Duke.Duke` and the UI in `MainWindow`. **Main.java** ```java @@ -182,7 +182,7 @@ import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; /** - * A GUI for Duke using FXML. + * A GUI for Duke.Duke using FXML. */ public class Main extends Application { diff --git a/tutorials/textUiTestingTutorial.md b/tutorials/textUiTestingTutorial.md index f397d76aef..d6c9e54ade 100644 --- a/tutorials/textUiTestingTutorial.md +++ b/tutorials/textUiTestingTutorial.md @@ -13,7 +13,7 @@ del ACTUAL.TXT REM compile the code into the bin folder - javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\Duke.java + javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\Duke.Duke.java IF ERRORLEVEL 1 ( echo ********** BUILD FAILURE ********** exit /b 1 @@ -21,7 +21,7 @@ REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT - java -classpath ..\bin Duke < input.txt > ACTUAL.TXT + java -classpath ..\bin Duke.Duke < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT @@ -44,14 +44,14 @@ fi # compile the code into the bin folder, terminates if error occurred - if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/Duke.java + if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/Duke.Duke.java then echo "********** BUILD FAILURE **********" exit 1 fi # run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT - java -classpath ../bin Duke < input.txt > ACTUAL.TXT + java -classpath ../bin Duke.Duke < input.txt > ACTUAL.TXT # compare the output to the expected output diff ACTUAL.TXT EXPECTED.TXT