diff --git a/README.md b/README.md index 13f5c77403f..309982c56ba 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,28 @@ -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) +# ManageEZPZ +[![CI Status](https://github.com/AY2122S2-CS2103-F11-1/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S2-CS2103-F11-1/tp/actions) +[![codecov](https://codecov.io/gh/AY2122S2-CS2103-F11-1/tp/branch/master/graph/badge.svg?token=ILZDIFELY7)](https://codecov.io/gh/AY2122S2-CS2103-F11-1/tp) ![Ui](docs/images/Ui.png) -* This is **a sample project for Software Engineering (SE) students**.
- Example usages: - * as a starting point of a course project (as opposed to writing everything from scratch) - * as a case study -* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details. - * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big. - * It comes with a **reasonable level of user and developer documentation**. -* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...). -* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**. -* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info. +ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java.
+ +Example usages: + +* add tasks such as Todos, Deadlines and Events +* view all tasks to have a better picture of the current schedule +* edit tasks when details of the said task has been updated +* mark and unmark the tasks as done or not done yet +* assign a task to an employee +* assign a priority to a task +* add employees which can be assigned tasks to +* view all employees to get their personal details and number of assigned tasks +* edit employees when personal details of the said employee has been updated + +Acknowledgment:
+ +This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org). + +The images used in ManageEZPZ are attributed as follows: + +- Employee icon, Priority icons, Phone icon and Email icon created by Jun Yang (member of the team) +- Task icon created by feen (Flaticon) and edited by Jun Yang to fill up colours and change stroke colour diff --git a/build.gradle b/build.gradle index be2d2905dde..28b0fae57d3 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id 'jacoco' } -mainClassName = 'seedu.address.Main' +mainClassName = 'manageezpz.Main' sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -66,7 +66,12 @@ dependencies { } shadowJar { - archiveName = 'addressbook.jar' + archiveName = 'ManageEZPZ.jar' + archiveVersion = "v1.4" +} + +run { + enableAssertions = true } defaultTasks 'clean', 'test' diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1c9514e966a..59fd1e81903 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -9,51 +9,57 @@ You can reach us at the email `seer[at]comp.nus.edu.sg` ## Project team -### John Doe +### Loke Jin Xue Aaron - + -[[homepage](http://www.comp.nus.edu.sg/~damithch)] -[[github](https://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/aaron-ljx)] +[[portfolio](team/aaron-ljx.md)] -* Role: Project Advisor +* Role: Developer +* Responsibilities: Deliverables and Deadlines +* In Charge of Component Logic -### Jane Doe +### Alfred Koh - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/alfredkohhh)] +[[portfolio](team/alfredkohhh.md)] -* Role: Team Lead -* Responsibilities: UI +* Role: Developer +* Responsibilities: Integration, Documentation, Deliverables and Deadlines +* In Charge of: Storage -### Johnny Doe +### Tay Jun Yang - + -[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)] +[[github](http://github.com/dannytayjy)] +[[portfolio](team/dannytayjy.md)] * Role: Developer -* Responsibilities: Data +* Responsibilities: Deliverables and Deadlines, Code Quality +* In Charge of Component UI -### Jean Doe +### Ng Wen Hao Dennis - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/denniszedead)] +[[portfolio](team/denniszedead.md)] * Role: Developer -* Responsibilities: Dev Ops + Threading +* Responsibilities: Deliverables and Deadlines, Quality Assurance +* In Charge of Component Logic -### James Doe +### Chan Wei Jie - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/chanweijie)] +[[portfolio](team/chanweijie.md)] * Role: Developer -* Responsibilities: UI +* Responsibilities: Integration, Documentation, Deliverables and Deadlines +* In Charge of Component Model diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 46eae8ee565..6fd8166f8f5 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -2,14 +2,11 @@ layout: page title: Developer Guide --- -* Table of Contents -{:toc} -------------------------------------------------------------------------------------------------------------------- ## **Acknowledgements** - -* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} +* [Documentation idea of splitting the Model component into 2, to prevent cramping of images](https://ay2021s2-cs2103t-t12-4.github.io/tp/DeveloperGuide.html#endpoint-components) -------------------------------------------------------------------------------------------------------------------- @@ -18,12 +15,13 @@ title: Developer Guide Refer to the guide [_Setting up and getting started_](SettingUp.md). -------------------------------------------------------------------------------------------------------------------- +
## **Design**
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams. +:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/AY2122S2-CS2103-F11-1/tp/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
### Architecture @@ -36,7 +34,7 @@ Given below is a quick overview of main components and how they interact with ea **Main components of the architecture** -**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for, +**`Main`** has two classes called [`Main`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/Main.java) and [`MainApp`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/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 methods where necessary. @@ -52,7 +50,7 @@ The rest of the App consists of four components. **How the architecture components interact with each other** -The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. +The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `deleteEmployee 1`. @@ -69,24 +67,26 @@ The sections below give more details of each component. ### UI component -The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java) +The **API** of this component is specified in [`Ui.java`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/ui/Ui.java)) ![Structure of the UI Component](images/UiClassDiagram.png) -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `TaskListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. -The `UI` component uses the 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`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) +The `UI` component uses the 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`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/resources/view/MainWindow.fxml). The `UI` component, * executes user commands using the `Logic` component. * listens for changes to `Model` data so that the UI can be updated with the modified data. * keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. +* depends on some classes in the `Model` component, as it displays `Task` object residing in the `Model`. + +
### Logic component -**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) +**API** : [`Logic.java`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/logic/Logic.java) Here's a (partial) class diagram of the `Logic` component: @@ -94,48 +94,52 @@ Here's a (partial) class diagram of the `Logic` component: How the `Logic` component works: 1. When `Logic` is called upon to execute a command, it uses the `AddressBookParser` class to parse the user command. -1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`. +1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddTodoTaskCommand`) which is executed by the `LogicManager`. 1. The command can communicate with the `Model` when it is executed (e.g. to add a person). 1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. -The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call. +The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("deleteTask 1")` API call. -![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png) +![Interactions Inside the Logic Component for the `addTask` Command](images/AddSequenceDiagram.png) -
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +
:information_source: **Note:** The lifeline for `DeleteTaskCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command: +
+ How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. -* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. +* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddTodoTaskCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddTodoTaskCommand`) which the `AddressBookParser` returns back as a `Command` object. +* All `XYZCommandParser` classes (e.g., `AddTodoTaskCommandParser`, `DeleteTaskCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. ### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) - +**API** : [`Model.java`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/model/Model.java) + + The `Model` component, * stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). +* stores the task list data i.e., all `Task` objects (which are contained in a `UniqueTaskList` object). * stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. +* stores the currently 'selected' `Task` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. * stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. * does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) -
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
- - - +
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `TaskList`, which `Task` references. This allows `TaskList` to only require one `Tag` object per unique tag, instead of each `Task` needing their own `Tag` objects.
+
+
### Storage component -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) +**API** : [`Storage.java`](https://github.com/AY2122S2-CS2103-F11-1/tp/blob/master/src/main/java/manageezpz/storage/Storage.java) @@ -143,10 +147,11 @@ The `Storage` component, * can save both address book data and user preference data in json format, and read them back into corresponding objects. * inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). * depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) +* `JsonAddressBookStorage` has a `JsonSerializableAddressBook`, which have `JsonAdaptedPerson` and `JsonAdaptedTask` to store and load both Persons and Tasks. ### Common classes -Classes used by multiple components are in the `seedu.addressbook.commons` package. +Classes used by multiple components are in the `manageezpz.commons` package. -------------------------------------------------------------------------------------------------------------------- @@ -154,90 +159,325 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa This section describes some noteworthy details on how certain features are implemented. -### \[Proposed\] Undo/redo feature +### **Task Components** +- Added Classes into the model Component to encapsulate a Task. -#### Proposed Implementation +#### **Implementation** + -The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations: +A `Task`, +- is stored in `uniqueTaskList` of the Model +- can be represented by a `Todo`, `Event`, or `Deadline` -* `VersionedAddressBook#commit()` — Saves the current address book state in its history. -* `VersionedAddressBook#undo()` — Restores the previous address book state from its history. -* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history. +A `Task` contains the following attributes, +1. a `Description`, which represent the details of the Task +2. a `Date`, which represent the day, month and year as specified by a number of the Task +3. a `Time`, which represent the period during the Task exists or happens +4. can be assigned/Tagged to multiple different `Person` +5. a type, to differentiate between the different types of task +6. can be marked/unmarked based on whether the task is done or not. +7. can be assigned to a single `Priority` such as "NONE", "LOW", "MEDIUM" or "HIGH" -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. +#### Design considerations: -Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. +#### Aspect: How the components within Task are added or changed +- **Current Choice**: Attributes within `Task` are immutable, meaning that if there is an attribute that has to be edited, a new Task object has to be created. + * Pros: Concept of Immutability is met, making the code less prone to bugs as all components of an Task object are fixed + * Cons: Less flexible, more steps needed in editing Task objects +- Alternative 1: Allow certain components within Task, like Time and Date to be mutable + * Pros: Less overhead as fewer objects are created + * Cons: Prone to error as a Component might not be correctly changed -Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state. +### Task Adding feature -![UndoRedoState0](images/UndoRedoState0.png) +#### What is Task Adding feature about? -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. +The Add Task mechanism is facilitated by `AddressBook`. This feature enhances `AddressBook` by allowing to store not only `Person`, but also `Task`. This is stored internally as a `UniquePersonList` and `UniqueTaskList`. Additionally, the feature implements the following operations: -![UndoRedoState1](images/UndoRedoState1.png) +* `AddressBook#addTodo(Todo)` —  Adds the `Todo` Task to `UniqueTaskList` +* `AddressBook#addDeadline(Deadline)` — Adds the `Deadline` Task to `UniqueTaskList` +* `AddressBook#addEvent(Event)` — Adds the `Event` Task to `UniqueTaskList` -Step 3. The user executes `add n/David …​` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. +For the command, the feature extends `command`, and is implemented as such: +* `addTodo desc/TASK_DESCRIPTION` +* `addDeadline desc/TASK_DESCRIPTION by/DATE TIME` +* `addEvent desc/TASK_DESCRIPTION at/DATE START_TIME END_TIME` -![UndoRedoState2](images/UndoRedoState2.png) +#### Implementation Flow of Task Adding feature -
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. +Given below is an example usage scenario and how the Task Adding mechanism behaves at each step. -
+Note: ManageEZPZ comes with preloaded data, and can be started on a fresh state with the `clear` command. -Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state. +Step 1. The user launches the application for the first time. ManageEZPZ will be initialized with the preloaded data. -![UndoRedoState3](images/UndoRedoState3.png) +Step 2. The user executes `addTodo desc/Watch Netflix with Mum` command to create a new `Todo` Task. +![AddTodo1](images/AddTodo.png) -
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather -than attempting to perform the undo. +#### Design considerations: +- The Task adding commands are straight-to-the-point and efficient for users to add Tasks to ManageEZPZ. +- The prefixes allow users to understand what the different types of Task need in order to be created. -
+#### UML Diagram for Adding Todo Task -The following sequence diagram shows how the undo operation works: +The following activity diagram summarizes what happens when a user executes a new `addTodo` command: -![UndoSequenceDiagram](images/UndoSequenceDiagram.png) + -
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +### Task Marking feature -
+#### What is Task Marking feature about? -The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state. +The Mark Task mechanism is facilitated by `AddressBook`. This feature allows the user to mark a task as done. -
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo. +For the command, the feature extends `command`, and is implemented as such: +* `markTask INDEX` -
+#### Implementation Flow of Task Marking feature -Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged. +Given below is an example usage scenario and how the Mark Task mechanism behaves at each step. -![UndoRedoState4](images/UndoRedoState4.png) +Step 1. The user lists all the task by listing the task with the 'list' command. -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern desktop applications follow. +Step 2. The user executes `markTask 3` command to mark the task `Meeting with Client` as done. -![UndoRedoState5](images/UndoRedoState5.png) +![](images/MarkTask.png) -The following activity diagram summarizes what happens when a user executes a new command: +#### Design considerations - +- The user is able to mark a task as done through the index number specified in the list view. -#### Design considerations: +#### UML Diagram for Task Marking + +![](images/MarkClassDiagram.png) + +### Task Unmarking feature + +#### What is Task Unmarking feature about? + +The Unmark Task mechanism is facilitated by `AddressBook`. This feature allows the user to unmark a task, which changes the status back to not done. + +For the command, the feature extends `command`, and is implemented as such: +* `unmarkTask INDEX` + +#### Implementation Flow of Task Unmarking feature + +Given below is an example usage scenario and how the Unmark Task mechanism behaves at each step. + +Step 1. The user lists all the task by listing the task with the 'list' command. + +Step 2. The user executes `unmark 3` command to unmark the task `Meeting with Client`, which changes the status back to not done. + +![](images/UnmarkTask.png) + +#### Design considerations + +- The user is able to unmark a task, which changes the status back to not done through the index number specified in the list view. + +#### UML Diagram for Task Unmarking + +![](images/UnmarkClassDiagram.png) + +### Task Deleting feature + +#### What is Task Deleting feature about? + +The Delete Task mechanism is facilitated by `AddressBook`. This feature allows the user to delete a task. + +For the command, the feature extends `command`, and is implemented as such: +* `deleteTask INDEX` + +#### Implementation Flow of Task Deleting feature + +Given below is an example usage scenario and how the Delete Task mechanism behaves at each step. + +Step 1. The user lists all the task by listing the task with the 'list' command. + +Step 2. The user executes `deleteTask 3` command to delete the task `Meeting with Client`. + +![](images/DeleteTask.png) + +#### Design considerations + +- The user is able to delete a task as through the index number specified in the list view. + +#### UML Diagram for Task Deleting + +![](images/DeleteClassDiagram.png) + +### Editing details of a task + +The edit mechanism is facilitated by `EditTaskCommandParser` and `EditTaskCommand`.
+`EditTaskCommandParser.parse()` - parses the input by the user and returns a `EditTaskCommand` object.
+`EditTaskCommand.execute()` - creates a new `Task` object based on the parsed user input and calls `Model.setTask()` +to replace the old `Task` object with the new `Task` object. + +The command is as follows: editTask [TASK_INDEX] desc/ [DESC] at/ [TIME] date/ [DATE] + +- [TASK_INDEX] must not be empty. +- At least one of [DESC], [TIME] and [DATE] should not be empty. +- desc/ [DESC], at/ [TIME] or date/ [DATE] may be omitted but all of them cannot be omitted at the same time. + +Below is a sequence diagram of the editing of a task. + +![EditTaskSequenceDiagram](images/EditTaskSequenceDiagram.png) + +Step 1. The user executes a `editTask 1 desc/ eat` to edit the 1st task in the address book. The `editTask` command +in `AddressBookParser` calls `EditTaskCommandParser.parse()` +and parses the task index which is given as 1 and the task description that the +user wants to edit his task with is parsed as a String with value eat. + +If either the description or the date or time was not provided by the user, then the default value +would be an empty String. Otherwise, it would be parsed as a String with value provided by the user. +It is not the responsibility of `EditTaskCommandParser.parse()` to ensure that the input provided by the user is valid. +It will however ensure that a `Task` index is provided and +at least the description or date or time has a corresponding value. + +Step 2. +In `LogicManager`, `EditTaskCommand.execute()` is called. This `EditTaskCommand` object is the one that was returned +by `EditTaskCommandParser.parse()`. Within the `execute()` method, there are 3 cases to consider. + +1. The task is of type Todo. +2. The task is of type Deadline. +3. The task is of type Event. + +Each case is being handled separately by its corresponding handler method. + +In general, what each handler method will do is to ensure that the input provided +by the user is valid and if so, create a new `Task` object with the given input and +call `model.setTask()` to replace the old `Task` object +with the new `Task` object. If there are some input which is not provided, then the default value would be the +same value as the old `Task` object. If any input is not valid, a `ParseException` is thrown. + +For `editTask 1 desc/ eat`, in step 1, we have obtained the task index which is given as 1. +Using `model.getFilteredTaskList().get(index)` we obtain a copy of the task that the user wants to edit. +Next, depending on what type the obtained task is, the corresponding handler method is called. + +If the task is of type Todo, then the handler method will create a new `Todo` object with the description value as +"eat", call `model.setTask()` and return a CommandResult showing that the update has been successful. + +If the task is of type Deadline, then the handler method will create a new `Deadline` object with the description +value as "eat", and the date and time values set to be the same +values from the copy obtained using `model.getFilteredTaskList().get(index)`. Then, `model.setTask()` is called and +return a CommandResult showing that the update has been successful. + +If the task is of type Event, then the handler method will create a new `Event` object with the description +value as "eat", and the date and time values set to be the same +value from the copy obtained using `model.getFilteredTaskList().get(index)`. Then, `model.setTask()` is called and +return a CommandResult showing that the update has been successful. + +![EditTaskDesc](images/EditTaskDesc.PNG) + + +Note: For the Event type, a String value with two time values corresponding to be the start and end time +separated with an **empty space** must be provided. Other than the time values being valid, +the range between the start and end time must be valid as well. For example, 1700 2000 is valid while 2000 1700 is not. + +### Finding tasks and employees features + +#### All about this feature + +The feature for finding task and employee uses the following two commands: +* `findTask`: Find tasks +* `findEmployee`: Finds employees + +`findEmployee` improves on the `find` feature in AB3 where instead on finding persons (on in the case of our project +manageezpz, we now refer persons as employees) based only on their names, we can also find employees based their other +two properties, phone number and email. + +`findTask` similarly searches tasks based on any of their attributes (as stated in the task implementation) +stated by the user. + +
+ +#### Design of the find feature + +The find feature utilizes mainly the following classes: +* Parser: + * Check whether the attributes for either task and employees as entered by the user are valid as stated in the `Task` + and `Person` (class to represent employee) respectively. + * The first class when user enters `findTask`/`findEmployee`. + * Parser will first check if at least one attribute is entered. + * After which, it will check whether the attributes entered are valid as implemented in the `Task` and `Person` method. + * If the user fails to enter any of the attributes, or enters an invalid attribute, the Parser class will collate all + the mistakes the user has made as error messages, and it will be shown to the user. + * Otherwise, the parser will create a predicate by indicating all attributes entered by the user and setting + attributes not specified by the user as null (use optional parameter if the programming language used permits). + * The parser class will then return a command class, using the predicate as the argument. + * `FindTaskCommandParser` for findTask and `FindEmployeeCommandParser` for findEmployee +* Command: + * Executes command by showing all tasks/employee based on the attributes specified by the user. + * `FindTaskCommand` for findTask and `FindEmployeeCommand` for findEmployee +* Predicate: + * The parser class creates this predicate which will be used to filter tasks/employees based on the attributes given. + * If the attribute is set to null, it will default to true, otherwise, the predicate will check whether the + task/employee has these attributes. + * The results from the attributes (or true if not specified) are and together to produce the result from the predicate. + * `TaskMultiplePredicate` for filtering task and `PersonMultiplePredicate` for filtering employees. + +#### Implementation flow for the find task/employee feature +Given below is the implementation of the find task command when the user enters `findTask todo/` + +1. The user input will be sent to `FindTaskCommandParser` +2. `FindTaskCommandParser` will note down that the task type to search. +3. Since the inputs that the user entered is valid, the parser will create a `TaskMultiplePredicate` task type `todo` + while setting the rest of the attributes to `null`. +4. The attribute will be used as the argument to create the `FindTaskCommand` +5. When the `FindTaskCommand` executes, the predicate will be sent to the `ModelManager` to filter out tasks that + satisfy the predicate. + +![Expected find task command result](images/FindTaskCommand.png) + +*The expected result for `findTask todo/`* + + +*The UML Sequence diagram for `findTask todo/`* + +#### Design Consideration +* Allow usage of multiple attributes as search term to filter out tasks/employee that has the specified attributes. +* Useful for finding tasks based on priority and whether it is marked or not. + +#### UML Diagram for finding task/employee + +![UML Diagram for finding task/employee](images/FindTaskClassDiagram.png) + +
-**Aspect: How undo & redo executes:** +### Tagging Task to Employee feature -* **Alternative 1 (current choice):** Saves the entire address book. - * Pros: Easy to implement. - * Cons: May have performance issues in terms of memory usage. +#### What is Tagging Task to Employee feature about? -* **Alternative 2:** Individual command knows how to undo/redo by - itself. - * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). - * Cons: We must ensure that the implementation of each individual command are correct. +The Tag Task mechanism is facilitated by `AddressBook`. +This feature enhances `AddressBook` by allowing users to assign multiple `Person` to a `Task`. Additionally, the feature implements the following operations: -_{more aspects and alternatives to be added}_ +* `AddressBook#tagTask(Task,Person)` —  Assign `Person` to `Task` +* `AddressBook#untagTask(Task,Person)` —  Deallocate the `Person` from `Task` -### \[Proposed\] Data archiving +For the command, the feature extends `command`, and is implemented as such: +* `tagTask INDEX name/PERSON_NAME` +* `untagTask INDEX name/PERSON_NAME` -_{Explain here how the data archiving feature will be implemented}_ +#### Implementation Flow of Tagging Task to Employee feature +Given below is an example usage scenario and how the Tagging Task to Employee mechanism behaves at each step. + +Note: ManageEZPZ comes with preloaded data, and can be started on a fresh state with the `clear` command. + +Step 1. The user launches the application for the first time. ManageEZPZ will be initialized with the preloaded data. + +Step 2. The user executes `tagTask 7 n/Alex Yeoh` command to assign `Alex Yeoh` to the 7th `Task`. +![AddTodo1](images/TagTask.png) + +#### Design considerations: +- The Tagging commands are efficient for users to assign a `Person` to be in-charge of a `Task`. +- The Prefix allow users to simply input the name of the `Person` from ManageEZPZ. +- Users will be able to see the `Task` assigned to `Person` immediately after tagging. + +#### UML Diagram for tagTask Command + +The following activity diagram summarizes what happens when a user executes a new `tagTask` command: + + -------------------------------------------------------------------------------------------------------------------- @@ -250,6 +490,7 @@ _{Explain here how the data archiving feature will be implemented}_ * [DevOps guide](DevOps.md) -------------------------------------------------------------------------------------------------------------------- +
## **Appendix: Requirements** @@ -257,73 +498,425 @@ _{Explain here how the data archiving feature will be implemented}_ **Target user profile**: -* has a need to manage a significant number of contacts -* prefer desktop apps over other types -* can type fast -* prefers typing to mouse interactions -* is reasonably comfortable using CLI apps +* Company Managers/Supervisors wants to keep track of all the tasks given to their subordinates +* They need to assign tasks to their subordinates as well +* Prefers typing commands instead of clicking buttons +* Needs a local database to store all tasks -**Value proposition**: manage contacts faster than a typical mouse/GUI driven app +**Value proposition**: +* An application to show all the tasks assigned to the employees +* Tasks should be assigned to the employees as well +* Commands are typed using command lines +* All tasks created are stored in the local database ### User stories Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` -| Priority | As a …​ | I want to …​ | So that I can…​ | -| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- | -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | 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 | 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 | +| Priority | As a …​ | I want to …​ | So that I can…​ | +|----------|----------------|----------------------------------------------------------------------------|---------------------------------------------------------------| +| `* * *` | user | add a task to the database | better organise my time | +| `* * *` | user | delete a task from the database | better organise my list | +| `* * *` | user | view all my tasks | have a better picture of my schedule | +| `* * *` | user | able to edit a task | update any details | +| `* * *` | user | able to view my tasks for the day (i.e. today) | better manage my time | +| `* * *` | user | able to view the tasks for the week | have a better picture of my schedule for the week | +| `* * *` | user | view the tasks on a specific day | plan for that day ahead | +| `* *` | CEO or manager | have the flexibility to reschedule tasks that are assigned to any employee | better manage the manpower and deadlines | +| `* *` | manager | retrieve the list of tasks allocated with an employee | allow myself to have an overview of the employee's workload. | +| `* *` | new user | have a more beginner-friendly user guide | learn more about the product | -*{More to be added}* ### Use cases -(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise) +> Definition: +> - For all use cases below, the **System** is `ManageEZPZ` and the **Actor** is the `User`, unless specified otherwise. +> - More specifically, the `User` are **Supervisors and Managers**. + +> Guarantees: +> - For any use cases below that changes any data, ManageEZPZ will guarantee that the data is updated and saved. +**** + +**Use Case 1 - Add Task** + +**MSS** + +1. User starts up ManageEZPZ +2. User uses the appropriate command to add Task. +3. ManageEZPZ adds the task & confirms with a successful message that the task is added. + + Use case ends. + +**Extensions** + +* 2a. User uses one of the three `add` commands: + * 2a1. User uses `addTodo` command + + Use case resumes from step 3. + + * 2a2. User uses `addDeadline` command + + Use case resumes from step 3. + + * 2a3. User uses `addEvent` command + + Use case resumes from step 3. + +* 2b. User uses Add Task Commands with the wrong syntax + + * 2b1. ManageEZPZ sends an error message to User, indicating the + format for adding Task is incorrect, attached with the correct syntax format. + + Use case ends. + +**** + +**Use Case 2 - Delete Task** + +Guarantees: Deletion of any Task will also result in the removal + of any Employee association that the Task has. + +**MSS** + +1. User starts up ManageEZPZ +2. User uses the appropriate command to delete a Task +3. ManageEZPZ deletes the Task & confirms with a successful message that the Task is deleted. + + Use case ends. + +**Extensions** + +* 2a. ManageEZPZ detects an error in the entered data. (Invalid index) + * 2a1. ManageEZPZ sends an error message to User, indicating the Index used for the delete + command is incorrect, attached with the correct syntax format. + + Use case ends. + +**** + +**Use Case 3 - List Tasks** -**Use case: Delete a person** +**MSS** + +1. User starts up ManageEZPZ +2. User enters the command to list Tasks. +3. ManageEZPZ displays the all Tasks. + + Use case ends. + +**Extensions** + +* 2a. User uses list Task commands with the wrong syntax. + * 2a1. ManageEZPZ sends an error message to User, that the list + command is incorrect, attached with the correct syntax format. + + Use case ends. + +**** + +**Use Case 4 - Mark Tasks** + +Preconditions: User is currently using ManageEZPZ. **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 enters the command to view Tasks. +2. ManageEZPZ displays the Tasks. +3. User wants to mark a Task as finished, enters command to mark Task. +4. ManageEZPZ marks the Task & confirms with a successful message that the task is marked - Use case ends. + Use case ends. **Extensions** -* 2a. The list is empty. +* 3a. ManageEZPZ detects an error in the entered data. (Invalid Index) - Use case ends. + * 3a1. ManageEZPZ sends an error message to User, indicating the Index used for + the Mark command is incorrect, attached with the correct syntax format. -* 3a. The given index is invalid. + Use Case ends. + +**** + +**Use Case 5 - Unmark Tasks** + +Preconditions: User is currently using ManageEZPZ. + +**MSS** + +1. User enters the command to view Tasks. +2. ManageEZPZ displays the Tasks. +3. User realises that Task is marked as done, but is actually not done. +4. User enters command to unmark Task for the specific Task Number. +5. ManageEZPZ unmarks the Task & confirms with a successful message + that the task is unmarked. + + Use case ends. + +**Extensions** - * 3a1. AddressBook shows an error message. +* 4a. ManageEZPZ detects an error in the entered data. (Invalid Index) - Use case resumes at step 2. + * 4a1. ManageEZPZ sends an error message to User, indicating the Index used for + the unmark command is incorrect, attached with the correct syntax format. -*{More to be added}* + Use Case ends. + +**** + +**Use Case 6 - Find Tasks** + +**MSS** + +1. User starts up ManageEZPZ +2. User enters the command to find Tasks. +3. ManageEZPZ displays the Task(s) which matches the search keyword. + + Use case ends. + +**Extensions** + +* 2a. User uses one of the three Find Task commands: + + * 2a1. User uses any of the `findTask` command: + * `findTask todo/` + * `findTask deadline/` + * `findTask event/` + * With or without the Task type above, the User wants to also get a more + filtered search result, User then adds these prefixes as additional + search terms: + * `desc/` for Description search. + * `date/` for Date search. + * `priority/` for Priority search. + * `assignees/` for Assignees search. + * `isMarked/` for finished Tasks Search. + + Use case resumes from step 3. + +* 2b. User uses find Task commands with the wrong syntax + + * 2b1. ManageEZPZ sends an error message to User, indicating syntax used for + the find Task command is incorrect, attached with the correct syntax format. + + Use Case ends. + +**** + +**Use Case 7 - Edit Tasks** + +**MSS** + +1. User starts up ManageEZPZ +2. User enters the command to list Tasks. +3. User realizes that some Tasks have the wrong information. +4. User enters the command to edit the Task(s). +5. ManageEZPZ sends a message to the User indicating that the edit has been successful. + + Use case ends. + +**Extensions** + +* 4a. User selects a combination of prefixes to edit: + * `desc/` to edit the Description. + * `at/` to edit the Time. + * `date/` to edit the Date. + + Use case resumes from step 5. + +* 4b. User uses edit Task commands with the wrong syntax + + * 4b1. ManageEZPZ sends an error message to User, indicating syntax used for + the edit Task command is incorrect, attached with the correct syntax format. + + Use Case ends. + +* 4c. User uses edit Task commands with prefix declared but no input value afterwards + + * 4c1. ManageEZPZ sends an error message to User, indicating that User must input a value after a prefix. + + Use Case ends. + +**** + +**Use Case 8 - Add Employee** + +Preconditions: User is currently using ManageEZPZ. + +**MSS** +1. User wants to add a new Employee, enters command to add Employee. +2. ManageEZPZ adds the Employee & confirms with a successful message that the + Employee is added to ManageEZPZ. + + Use case ends. + +**Extensions** + +* 1a. ManageEZPZ detects an error in the entered data. + + * 1a1. ManageEZPZ sends an error message to User, indicating the + format for the add Employee command is incorrect, attached with the + correct syntax format. + + Use Case ends. + +**** + +**Use Case 9 - Deleting Employee** + +Preconditions: User is currently using ManageEZPZ. + +Guarantees: Deletion of any Employee will also result in the removal + of the Employee from the Task(s) that the Employee has been + assigned to. + +**MSS** +1. User wants to delete an existing Employee, enters command to delete Employee. +2. ManageEZPZ deletes the Employee and sends a confirmation message that the + deletion has been successful. + + Use case ends. + +**Extensions** + +* 1a. ManageEZPZ detects an error in the entered data. + + * 1a1. ManageEZPZ sends an error message to User, indicating the + format for delete Employee command is incorrect, attached with the + correct syntax format. + + Use Case ends. + +**** + +**Use Case 10 - Tagging Employee to Task** + +Preconditions: User is currently using ManageEZPZ. + +**MSS** + +1. User enters the command to tag an Employee to a Task. +2. ManageEZPZ assigns the Employee to the Task, and sends a confirmation message + to the User that the Employee has been assigned. + + Use case ends. + +**Extensions** + +* 1a. ManageEZPZ detects an error in the entered data. + + * 1a1. ManageEZPZ sends an error message to User, indicating the + format for the tag Employee to Task command is incorrect, attached with the + correct syntax format. + * 1a2. ManageEZPZ detects that supplied Task Index is not in the Task List, + indicating to the User to enter a valid Task number. + * 1a3. ManageEZPZ detects that Name of Employee is not in the database, + indicating to the User to enter a valid Employee Name. + + Use Case ends. + +**** + +**Use Case 11 - Tagging Priority to Tasks** + +Preconditions: User is currently using ManageEZPZ. + +**MSS** + +1. User enters the command to Tag a Priority to a Task. +2. ManageEZPZ tags the appropriate Priority to the Task, and sends a + confirmation message to the Priority has been assigned to the Task. + + Use case ends. + +**Extensions** + +* 1a. ManageEZPZ detects an error in the entered data. + + * 1a1. ManageEZPZ sends an error message to User, indicating the + format for the add Employee command is incorrect, attached with the + correct syntax format. + * 1a2. ManageEZPZ detects that supplied Task Index is not in the Task List, + indicating to the User to enter a valid Task number. + * 1a3. ManageEZPZ detects that an invalid Priority that is not one of the four: + None, Low, Medium, High. ManageEZPZ reminds the User to use a valid + Priority. + + Use Case ends. + +**** + +**Use Case 12 - Deleting all Entries in ManageEZPZ** + +Preconditions: User is currently using ManageEZPZ. + +**MSS** + +1. User enters the command to clear ManageEZPZ. +2. ManageEZPZ clears all Employee and Task data, sending a confirmation + message that ManageEZPZ entries are cleared. + + Use case ends. + +**** + +**Use Case 13 - Exit ManageEZPZ** + +Preconditions: User is currently using ManageEZPZ. + +**MSS** + +1. User enters a command to exit ManageEZPZ. +2. ManageEZPZ saves all changes to disk and closes. + + Use case ends. + +**** ### Non-Functional Requirements -1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -2. Should be able to hold up to 1000 persons 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. +#### Technical Requirements + +1. ManageEZPZ should be able to run on any _mainstream OS_ as long as it has Java `11` or above installed. +2. ManageEZPZ should work on both 32-bit and 64-bit environments. +3. ManageEZPZ should be able to store and retrieve task data from File. +4. ManageEZPZ must occupy as little storage as possible. +5. ManageEZPZ should be backward compatible with data produced by earlier versions of itself. + +#### Performance Requirements -*{More to be added}* +1. ManageEZPZ should respond within two seconds for any queries. + * ManageEZPZ should be closed/terminated within 2 seconds. +2. ManageEZPZ should work well under both normal and high workloads. +3. ManageEZPZ should be scalable. +4. ManageEZPZ should be able to load huge amounts of data in a short amount of time. + +#### Quality Requirements + +1. ManageEZPZ should be easy to use by a novice. +2. ManageEZPZ should be in English. +3. The UI and fonts used in ManageEZPZ should be big enough for senior managers/supervisors. + +#### Process Requirements + +1. ManageEZPZ is expected to adhere to a schedule that delivers a feature set every 2 weeks. +2. Updates to ManageEZPZ should be able to roll out to existing clients remotely. + +#### Other Noteworthy Points + +1. ManageEZPZ should not be used to support management of illegal activities. ### Glossary -* **Mainstream OS**: Windows, Linux, Unix, OS-X -* **Private contact detail**: A contact detail that is not meant to be shared with others +| Terms | Meaning | +|:------------------|:---------------------------------------------------------------------------| +| **Mainstream OS** | Windows, Linux, Unix, OS-X | +| **Users** | Applies to both managers or supervisors | +| **command** | A message sent as an input from User, that coincides with our Command List | +| **Person** | An employee | -------------------------------------------------------------------------------------------------------------------- +
## **Appendix: Instructions for manual testing** @@ -336,42 +929,268 @@ testers are expected to do more *exploratory* testing. ### Launch and shutdown -1. Initial launch +1. Test case : Initial launch + 1. [Download](https://github.com/AY2122S2-CS2103-F11-1/tp/releases) the jar file and copy into an empty folder + 2. Double-click the jar file
+ Expected: Shows the GUI with a set of sample Employees and Tasks. The window size may not be optimum. - 1. Download the jar file and copy into an empty folder - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. +2. Test case : Saving window preferences + 1. Resize the window to an optimum size. Move the window to a different location. Close the window. + 2. Re-launch the app by double-clicking the jar file.
+ Expected: The most recent window size and location is retained. + -1. Saving window preferences +3. Test case : Shutdown + 1. Click the cross button at top right side of window for WindowsOS, and top left side of window for MacOS. + + 2. Type `exit` command in the command box in GUI. + Expected: The programs stops executing and closes. - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. +### Adding an employee + +1. Adding an employee while all employees are being shown + + 1. Prerequisites: List all employee using the `listEmployee` command. Multiple employees in the list. + + 2. Test case: `addEmployee n/Peter Tan p/97852145 e/PeterTan@gmail.com`
+ Expected: A new `Employee` is added to the end of the list. Details of the newly added `Deadline` shown in the status message. GUI immediately updates to show the newly added `Employee`. + + 3. Test case: `addEmployee n/Peter Tan`
+ Expected: No employee is added. Error details shown in the status message. GUI remains the same. + + 4. Other incorrect delete commands to try: `addEmployee p/98451254`, `addEmployee e/PeterTan@gmail.com`, `addEmployee n/Peter p/85245127`
+ Expected: Similar to previous. + +### Listing all employees + +1. List down all employees + 1. Prerequisites: Filter employees using `findEmployee` command. + 2. Test Case: `listEmployee`
+ Expected: Shows all the employees in ManageEZPZ + +### Finding employees + +1. Find employees with the given predicate + + 1. Prerequisites: List all employees using the `listEmployee` command. + + 2. Test case: `findEmployee`
+ Expected: Error showing that at least an option is needed. + + 3. Valid test cases to try: `findEmployee n/Alice`, `findEmployee p/999`, `...` (So long as the task attribute are + valid)
+ Expected: All employees with the specified attributes will be listed. + + 4. Other invalid test cases to try: `findEmployee someOtherPrefix/`, `findEmployee n/Jame$`, `...` (So long as the + attribute are invalid)
+ Expected: Error showing which attributes are entered wrongly. + +### Deleting an employee + +1. Deleting an employee while all employee are being shown + + 1. Prerequisites: List all employee using the `listEmployee` command. Multiple employees in the list. + + 1. Test case: `deleteEmployee 1`
+ Expected: First employee is deleted from the list. Details of the deleted employee shown in the status message. GUI immediately updates to show the employee is deleted. + + 1. Test case: `deleteEmployee 0`
+ Expected: No employee is deleted. Error details shown in the status message. GUI remains the same. + + 1. Other incorrect delete commands to try: `deleteEmployee`, `deleteEmployee x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous. + +### Adding a Task (Deadline) +1. Adding a `Deadline` +2. Prerequisites: None. + +3. Test case : Adding a valid deadline + 1. Command: `addDeadline desc/Testing by/2020-08-08 1800`
+ Expected: A new `Deadline` is added to the end of the list. Details of the newly added `Deadline` shown in the status message. GUI immediately updates to show the newly added `Deadline`. + + +4. Test case : invalid date + 1. Command: `addDeadline desc/Testing by/0000-14-08 1800`
+ Expected: No `deadline` is added. Error details shown in the status message. GUI stays the same. + + +5. Test case : invalid time + 1. Command: `addDeadline desc/Testing by/2020-12-08 6000`
+ Expected: No `deadline` is added. Error details shown in the status message. GUI stays the same. + + +6. Other incorrect addDeadline commands to try: `addDeadline desc/`, `addDeadline desc/Testing by/`
+ Expected: Similar to previous. + +### Listing all tasks + +1. List down all tasks + 1. Prerequisites: Filter tasks using `findTask` command. + 2. Test Case: `listTask`
+ Expected: Shows all the tasks in ManageEZPZ + +### Finding tasks +1. Prerequisites: None, but if the task list is empty, all searches will lead to no results. +2. List all task using the `listTask` command. +3. Test case : Find by a single keyword. + 1. Command `findTask todo/`
+ Expected: Task list will show all tasks that are of type `todo`. Find task details shown in status message. GUI immediately updates to show only `todo` type tasks. + 2. Command `findTask desc/report`
+ Expected: Task list will show all tasks that have the description of `report`. Find task details shown in status message. GUI immediately updates to show all task with description `report`. - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. -1. _{ more test cases …​ }_ +4. Test case : Find by multiple keywords. + 1. Command: `findTask deadline/ desc/report`
+ Expected: Task list will show all task with type `deadline` & description of `report`. Find task details shown in status message. GUI immediately updates to show all task of type `deadline` with description `report`. + 2. Command : `findTask deadline/ date/2022-05-05`
+ Expected: Task list will show all task with type `deadline` & date of `2022-05-05`. Find task details shown in status message. GUI immediately updates to show all task of type `deadline` with date `2020-05-05`. -### Deleting a person -1. Deleting a person while all persons are being shown +5. test case : Invalid command formats. + 1. Command: `findTask`
+ Expected: No task would be found. Error details shown in status message. GUI stays the same. + 2. Other incorrect findTask commands to try: `findTask todo/ deadline/`, `findTask isMarked/maybe`
+ Expected: Similar to previous. - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. +### Editing a task +1. Prerequisites: None. +2. List all task using the `listTask` command. +3. Test case : Edit task description + 1. Condition: the edited task description must not already exist in the task list. + 2. Command: `editTask 1 desc/Complete Sales Report`
+ Expected: Description of Task at index 1 is changed to `Complete Sales Report`. Edited task details shown in status message. GUI immediately updates to show newly edited Task. - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. +4. Test case : Edit task time + 1. Condition : The task to be edited must be of either `Deadline` or `Event` type. + 2. Command: `editTask 1 at/1700`
+ Expected: Time of Task at index 1 is changed to `1700`. Edited task details shown in status message. GUI immediately updates to show newly edited Task. - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. -1. _{ more test cases …​ }_ +5. Test case : Edit task date + 1. Condition : The task to be edited must be of either `Deadline` or `Event` type. + 2. Command: `editTask 1 date/2022-02-05`
+ Expected: Date of Task at index 1 is changed to `2022-02-05`. Edited task details shown in status message. GUI immediately updates to show newly edited Task. + + +6. Test case : Invalid edit index + 1. Condition : index provided exceeds the task list size or index are not positive. + 2. Command: `editTask 0 at/1700`, `editTask -4 date/2022-02-05`, `editTask desc/Complete Sales Report`
+ Expected: No task is edited. Error details shown in the status message. GUI stays the same. + + +7. Other incorrect editTask commands to try: `editTask 1 desc/`, `editTask 1 date/0000-01-01`, `editTask 1 time/2549`
+ Expected: Similar to previous. + +### Marking a Task +1. Prerequisites: None. +2. List all task using the `listTask` command. +3. Test case : Marking a valid task. + 1. Condition : None. + 2. Command: `markTask 1`
+ Expected: Task at index 1 is marked as done. Edited task details shown in status message. GUI immediately updates status from not done to done. + + +4. Test case : Invalid mark index + 1. Condition : index provided exceeds the task list size or index are not positive. + 2. Command: `markTask 0`, `markTask -4`, `markTask `
+ Expected: No task marked. Error details shown in the status message. GUI stays the same. + +### Deleting a Task +1. Prerequisites: List all tasks using the `listTask` command. Multiple tasks in the list. + +2. Test case: `deleteTask 1`
+ Expected: First task is deleted from the list. Details of the deleted task shown in the status message. GUI immediately updates to show that the task is deleted. + + +3. Test case: `deleteTask 0`
+ Expected: No task is deleted. Error details shown in the status message. GUI remains the same. + + +4. Other incorrect delete commands to try: `deleteTask `, `deleteTask x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous. + +### Tagging a task to an Employee +1. Prerequisites: None, but if the task list or employee list is empty, all tagging will lead to an error. +2. List all task using the `listTask` command. +3. List all employee using the `listEmployee` command. +4. Test case : valid Task & valid Employee + 1. Command: `tagTask 1 n/ Alex Yeoh`
+ Expected: Tags the Task at index 1 to Alex Yeoh. Tagged task details shown in status message. GUI immediately updates assignees field of the task at index 1. + + +5. Test case : invalid tag index + 1. Condition : index provided exceeds the task list size or index are not positive. + 2. Command: `tagTask 0 n/ Alex Yeoh`, `tagTask -4 n/ Alex Yeoh`, `tagTask n/ Alex Yeoh`
+ Expected: No task tagged. Error details shown in the status message. GUI stays the same. + + +6. Test case : valid Task & invalid Employee + 1. Condition : employee provided not in the employee list. + 2. Command: `tagTask 1 n/Alex Yeog`
+ Expected: Similar to previous. + + +7. Other incorrect tagTask commands to try: `tagTask 1 n/`, `tagTask 1 n/ Alex`(Full name not used)
+ Expected: Similar to previous. + + +### Tagging a priority to a Task. +1. Prerequisites: None, but if the task list is empty, all tagging will lead to an error. +2. List all task using the `listTask` command. +3. Test case : Valid Priority + 1. Command: `tagPriority 1 priority/HIGH`
+ Expected: Tags the Task at index 1 to priority of HIGH. Tagged task details shown in status message. GUI immediately updates priority fields of the task at index 1. + + +4. Test case : Invalid tag index + 1. Condition : index provided exceeds the task list size or index are not positive. + 2. Command: `tagPriority 1 priority/HIGH`, `tagPriority -4 priority/HIGH`, `tagTask priority/HIGH`
+ Expected: No task tagged. Error details shown in the status message. GUI stays the same. + + +5. Test case : Invalid Priority + 2. Command: `tagPriority 1 priority/Important`
+ Expected: Similar to previous. ### Saving data -1. Dealing with missing/corrupted data files +1. Dealing with corrupted data files + + 1. Test case : `ManageEZPZ.json` is edited incorrectly while the program is running.
+ Expected: No issues caused. Upon closing and re-launching the program, `ManageEZPZ.json` will be updated to an empty json file. + + +2. Dealing with missing data files + 1. Prerequisites : JSON file is missing. + 1. Delete the `data/ManageEZPZ.json` to simulate the missing json file. + 2. Relaunch the program.
+ Expected: ManageEZPZ starts with a default json list containing default Employees and Tasks. + + +3. Saving data between sessions + 1. Launch the program. + 2. Modify the Employee list or Task list by using any commands that will affect the out come of both lists. + 3. Relaunch the app.
+ Expected: ManageEZPZ would retain the recent changes. + +
+ +## **Appendix: Effort** + +**Difficulty Level** : + +While AB3 deals with only one entity type, `Persons`, ManageEZPZ deals with multiple entity types, including `Todos`, `Deadlines`, `Events` and `Tasks`. +The inclusion of the Task model has definitely increased the functionality but at the same time the difficulty of the project when compared to AB3 which +only had the `Persons` model. + +**Challenges faced** : + +As more features were implemented, we faced challenges that arose from the dependencies between the `Person` and `Tasks` classes in order to make ManageEZPZ's functionalities more user-centric and convenient for users (e.g. Deleting an Employee also results in deletion of an assignee from the task that was assigned to the employee and vice versa where Deleting a Task results in the decrement of the total number of task assigned to an Employee.) +Many of the bugs we encountered at the beginning of the project were also due to unfamiliarity with the code base and having to unearth the many layers of AB3, but as time went by, identified bugs have been resolved to result in the ManageEZPZ application today. + - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ +**Effort Required** : -1. _{ more test cases …​ }_ +Our MangeEZPZ Team has also spent a considerable amount of effort on the UI aspect, from choosing the position of the additional Task list (ultimately settling on a split UI), to the different pictures and colour scheme that was used to represent the different fields such as done/not done, priority, etc. So that it is the most appropriate to our users. diff --git a/docs/SettingUp.md b/docs/SettingUp.md index 275445bd551..1be8789c956 100644 --- a/docs/SettingUp.md +++ b/docs/SettingUp.md @@ -23,7 +23,7 @@ If you plan to use Intellij IDEA (highly recommended): 1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
:exclamation: Note: Importing a Gradle project is slightly different from importing a normal Java project. 1. **Verify the setup**: - 1. Run the `seedu.address.Main` and try a few commands. + 1. Run the `manageezpz.Main` and try a few commands. 1. [Run the tests](Testing.md) to ensure they all pass. -------------------------------------------------------------------------------------------------------------------- diff --git a/docs/Testing.md b/docs/Testing.md index 8a99e82438a..755219e61ae 100644 --- a/docs/Testing.md +++ b/docs/Testing.md @@ -29,8 +29,8 @@ There are two ways to run tests. This project has three types of tests: 1. *Unit tests* targeting the lowest level methods/classes.
- e.g. `seedu.address.commons.StringUtilTest` + e.g. `manageezpz.commons.StringUtilTest` 1. *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. `manageezpz.storage.StorageManagerTest` 1. 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. `manageezpz.logic.LogicManagerTest` diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3716f3ca8a4..52f1b9a4ace 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,10 +3,7 @@ layout: page title: User Guide --- -AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps. - -* Table of Contents -{:toc} +ManageEZPZ is a **desktop app for that allows managers or supervisors to manage employees and assign tasks to them. Optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). -------------------------------------------------------------------------------------------------------------------- @@ -14,27 +11,30 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo 1. Ensure you have Java `11` or above installed in your Computer. -1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases). +2. Download the latest `ManageEZPZ.jar` from [here](https://github.com/AY2122S2-CS2103-F11-1/tp/releases). + +3. Copy the file to the folder you want to use as the _home folder_ for your ManageEZPZ. -1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook. +4. Double-click the file to start the app. -1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png) +5. Start communicating with ManageEZPZ using the command box. -1. 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.
+6. 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.
Some example commands you can try: - * **`list`** : Lists all contacts. + * **`listTask`** : Lists all Tasks. - * **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book. + * **`addEmployee`**`n/John Doe p/98765432 e/johnd@example.com` : Adds a contact named `John Doe` to ManageEZPZ. - * **`delete`**`3` : Deletes the 3rd contact shown in the current list. + * **`deleteTask`**`3` : Deletes the 3rd Task shown in the Task list. - * **`clear`** : Deletes all contacts. + * **`clear`** : Deletes **ALL** data from ManageEZPZ. + + * **`addTodo desc/read book`** : Adds a todo task with a description of `read book` to the Task list. - * **`exit`** : Exits the app. + * **`tagTask 1 n/John Doe`** : Assigns the first task on the task list to an employee named John Doe. -1. Refer to the [Features](#features) below for details of each command. + * **`exit`** : Exits the app. -------------------------------------------------------------------------------------------------------------------- @@ -45,106 +45,362 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo **:information_source: Notes about the command format:**
* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. - -* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. - -* Items with `…`​ after them can be used multiple times including zero times.
- e.g. `[t/TAG]…​` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. + e.g. in `addEmployee n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. -* Parameters can be in any order.
+* Parameters for adding employees can be in any order.
e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. * If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken. -* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
+* Extraneous parameters for commands that do not take in parameters (such as `help`, `exit` and `clear`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`. +* Task related commands must be strictly lower case. + +* Task related parameters must be in sequence as shown in the instruction. + +* Parsing parameters of a task is done using the keywords such as `desc/`, `by/` & `at/`, as such, the parsing mechanism would take everything inserted after the keywords. + +* All indexes are int based, as such the maximum value is 2147483647 (231 - 1). + +* Employee `Names` and Task `Description` are case-sensitive. +
+
+ ### Viewing help : `help` -Shows a message explaning how to access the help page. +Shows a message explaining how to access the user guide and copying employee details to Computer Clipboard. -![help message](images/helpMessage.png) +![help message](images/helpMessage_new.png) Format: `help` +
-### Adding a person: `add` +### Adding an Employee : `addEmployee` -Adds a person to the address book. +Adds an employee to ManageEZPZ. -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​` +Note: +- Adding a duplicated Employee will result in an error. -
:bulb: **Tip:** -A person can have any number of tags (including 0) -
+Format: `addEmployee n/NAME p/PHONE_NUMBER e/EMAIL` Examples: -* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` -* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal` +* `addEmployee n/John Doe p/98765432 e/johnd@example.com` +* `addEmployee p/98754123 n/Betsy Crowe e/betsycrowe@example.com` -### Listing all persons : `list` +### Listing all Employees : `listEmployee` -Shows a list of all persons in the address book. +Shows a list of all employees in ManageEZPZ. -Format: `list` +Format: `listEmployee` -### Editing a person : `edit` +### Finding Employees by multiple options : `findEmployee` -Edits an existing person in the address book. +Finds employee(s) based on multiple conditions provided. -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…​` +Note: +* Parameters for finding employees can be entered together in any order. +* You must enter at least one parameter. +* Names are case-insensitive -* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …​ -* 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. +Format: `findEmployee n/NAMES p/PHONE_NUMBER e/EMAIL` +* `findEmployee n/[LIST OF NAMES]` finds employees whose names contain any of the words in [LIST OF NAMES]. +* `findEmployee p/PHONE_NUMBER` finds employees with the exact phone number. +* `findEmployee e/EMAIL` finds employees with the exact email. Examples: -* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively. -* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. +* `findEmployee n/Alex` +* `findEmployee p/87438807` +* `findEmployee e/alexyeoh@example.com` +* `findEmployee n/Bernice Yu p/99272758 e/berniceyu@example.com` -### Locating persons by name: `find` +### Editing an Employee : `editEmployee` -Finds persons whose names contain any of the given keywords. +Edits an existing employee in ManageEZPZ. -Format: `find KEYWORD [MORE_KEYWORDS]` +Format: `editEmployee INDEX n/NAME p/PHONE_NUMBER e/EMAIL` -* The search is case-insensitive. e.g `hans` will 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 Bo` will return `Hans Gruber`, `Bo Yang` +* Edits the employee at the specified INDEX. +* The index refers to the index number shown in the displayed employee list. +* The index **must be a positive integer** 1, 2, 3, …​ +* Existing values will be updated to the input values. +* All tasks that are assigned to the edited employee will be updated to reflect the new changes of the employee. +* No 2 Employees should have the same name, phone number or email. Examples: -* `find John` returns `john` and `John Doe` -* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png) +* `editEmployee 1 p/91234567 e/johndoe@example.com` edits the phone number and email address of the 1st employee to be 91234567 and johndoe@example.com respectively. All tasks that are assigned to the 1st employee will be updated to reflect the new changes of the employee. +* `editEmployee 2 n/Betsy Crower` edits the name of the 2nd employee to be Betsy Crower. All tasks that are assigned to the 2nd employee will be updated to reflect the new changes of the employee. -### Deleting a person : `delete` +### Deleting an Employee : `deleteEmployee` -Deletes the specified person from the address book. +Deletes the specified employee from ManageEZPZ. -Format: `delete INDEX` +Format: `deleteEmployee INDEX` -* Deletes the person at the specified `INDEX`. +* Deletes the employee at the specified INDEX. * The index refers to the index number shown in the displayed person list. * The index **must be a positive integer** 1, 2, 3, …​ +* All tasks that are assigned to the deleted employee will be updated to remove the employee from the respective tasks. + +Examples: +* `deleteEmployee 2` deletes the 2nd employee in the displayed employee list. All tasks that are assigned to the 2nd employee will be updated to remove the employee from the respective tasks. +* `listEmployee` followed by `deleteEmployee 2` sets the displayed employee list to show all employees in ManageEZPZ and deletes the 2nd employee in ManageEZPZ. All tasks that are assigned to the 2nd employee will be updated to remove the employee from the respective tasks. +* `findEmployee n/Betsy` followed by `deleteEmployee 1` sets the displayed employee list with the results from the findEmployee command and deletes the 1st employee in the displayed employee list. All tasks that are assigned to the 1st employee will be updated to remove the employee from the respective tasks. + +
+ +### Adding a Task : `addTodo`, `addEvent`, `addDeadline` + +Adds a task to ManageEZPZ. + +Format: +* `addTodo desc/TASK_DESCRIPTION` +* `addDeadline desc/TASK_DESCRIPTION by/DATE TIME` +* `addEvent desc/TASK_DESCRIPTION at/DATE START_TIME END_TIME` + +Examples: +* `addTodo desc/Powerpoint Slides for Company XYZ` +* `addDeadline desc/Client Proposal Slides by/2022-03-20 1800` +* `addEvent desc/Business Meeting at/2022-02-18 1900 2000` + +
+ +**:bulb: Take Note:**
+ +For creation of Tasks, ManageEZPZ will allow past deadlines and events to be added for the Managers to track.
+ +For Deadline and Event, the DATE must be in this format: YYYY-MM-DD
+ +For Deadline and Event, any TIME related fields must be in the format HHmm, where HH should only be between 00 and 23 and mm should only be between 00 and 59.

+ +For event, the START_TIME must be earlier than the END_TIME.

+ +Adding a duplicate Task will result in an error. + +
+ +### Listing all Tasks : `listTask` + +Shows a list of all tasks in ManageEZPZ. + +Format: `listTask` + +
+ +### Finding Tasks by multiple options : `findTask` + +Finds task(s) based on multiple conditions provided. + +Note: +* Parameters for finding tasks can be entered together in any order. +* You must enter at least one parameter from either Task Type or the valid options. +* Task Type is optional, however, when entered, only one task type is allowed. +* The first option must be valid. +* After the first valid option, any other invalid options that is not stated below will be ignored. + +Task Type Available: +* `todo/`: Todos +* `deadline/`: Deadlines +* `event/`: Events + +Options: +* `desc/`: Description of the tasks +* `date/`: Date of the task in YYYY-MM-DD (only for deadline and event) +* `priority/`: Priority of task, only `HIGH`, `MEDIUM`, `LOW` and `NONE` +* `assignees/`: The assignees that was assigned to the task (only one full name of assignee allowed) +* `isMarked/`: Whether the task is marked, only `true` or `false` + +Format: +* `findTask todo/` finds all todos +* `findTask deadline/` finds all deadlines +* `findTask event/` find all events +* `findTask desc/[LIST OF WORDS]` finds all tasks which contain any of the words in [LIST OF WORDS]. +* `findTask date/YYYY-MM-DD` finds all deadlines and events with the date +* `findTask priority/PRIORITY` find all tasks with the given PRIORITY [HIGH, MEDIUM, LOW, NONE] +* `findTask assignees/ASSIGNEE FULL NAME` finds all tasks assigned to the stated assignee (in full name) +* `findTask isMarked/true` finds all tasks that is already marked as done. +* `findTask isMarked/false` finds all tasks that is already marked as not done. + +
+ +Example: +* `findTask desc/homework` +* `findTask date/2022-04-16` +* `findTask desc/work priority/HIGH` +* `findTask deadline/ desc/school date/2022-04-16 priority/HIGH assignees/Alex Yeo isMarked/true` + * Finds the task with a description that contains all the following options: + * Task type of deadline, + * description which contains the word “school”, + * date 2022-04-16, + * priority high, + * assigned to Alex Yeoh, + * and is marked as done. + +### Editing a Task : `editTask` + +Edits an existing task in ManageEZPZ. + +Formats: +* `editTask INDEX desc/NAME` +* `editTask INDEX desc/NAME date/DATE` +* `editTask INDEX desc/NAME date/DATE at/TIME` +* `editTask INDEX date/DATE` +* `editTask INDEX date/DATE at/TIME` +* `editTask INDEX at/TIME` + +Editing tasks is flexible in ManageEZPZ. +For example, you can update just the task description or perhaps +just the date and time of the task only.
+However, you are not allowed to edit a task with no prefix supplied or if you have supplied a prefix, +a corresponding input after the prefix must exist.
+Either one of `desc/NAME`, `date/DATE` or `at/TIME` must exist. + +Note: +* For Deadline and Event, any TIME related fields must be in the format HHmm, where HH should only be between 00 and 23 + and mm should only be between 00 and 59. +* For Todo, you are not allowed to use `date/DATE` and/or `at/TIME` as it does not have a date +and time field to be edited. +* You can update a task to the same description, date and/or time. + +
+ +Examples:
+ +Given a task list as follows...
+ +1. Type: `Todo`, Description: `Eat Bread` +2. Type: `Deadline`, Description: `Chemistry Homework`, Date: `2022-05-03`, Time: `1700` +3. Type: `Event`, Description: `Final Exam`, Date: `2022-06-04`, Time: `1700 2000` + +* `editTask 1 desc/Drink Water` edits the task description of a `Todo` task. +* `editTask 2 date/2022-05-10 at/2000` edits the date and the time of a `Deadline` task. +* `editTask 3 at/1800 2100` edits the time of an `Event` task. + +
+ +**:bulb: Take Note:**
+ +For Deadline and Event, the DATE must be in this format: YYYY-MM-DD

+ +For Deadline and Event, any TIME related fields must be in the format HHmm, where HH should only be between 00 and 23 and mm should only be between 00 and 59.

+ +For Event, the START_TIME must be earlier than the END_TIME.

+ +Editing a Task to another already existing task will result in an error. + +
+ +### Marking a Task : `markTask` + +Marks the specified task in ManageEZPZ as done. + +Format: `markTask INDEX` + +* Marks the task at the specified `INDEX` as done. +* The index refers to the index number shown in the displayed task list. +* The index **must be a positive integer** 1, 2, 3, …​ +* Marking a marked task (i.e., that is already set as done) will not change its physical state. Examples: -* `list` followed by `delete 2` deletes the 2nd person in the address book. -* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command. +* `markTask 2` marks the 2nd task in the displayed task list as done. +* `listTask` followed by `markTask 2` sets the displayed task list to show all tasks in ManageEZPZ and marks the 2nd task in ManageEZPZ as done. +* `findTask desc/slides` followed by `markTask 1` sets the displayed task list with the results from the findTask command and marks the 1st task in the displayed task list as done. + +
+ +### Unmarking a Task : `unmarkTask` + +Unmarks the specified task in ManageEZPZ, i.e., changes the status back to not done. + +Format: `unmarkTask INDEX` + +* Unmarks the task at the specified `INDEX` to change the status back to not done. +* The index refers to the index number shown in the displayed Task list. +* The index **must be a positive integer** 1, 2, 3, …​ +* Unmarking an unmarked task (i.e., that is already set as not done) will not change its physical state. + +Examples: +* `unmarkTask 2` changes the 2nd task in the displayed task list back to not done. +* `listTask` followed by `unmarkTask 2` sets the displayed task list to show all tasks in ManageEZPZ and changes the 2nd task in ManageEZPZ back to not done. +* `findTask desc/slides` followed by `unmarkTask 1` sets the displayed task list with the results from the findTask command and changes the 1st task in the displayed task list back to not done. + +
+ +### Deleting a Task : `deleteTask` + +Deletes the specified task from ManageEZPZ. + +Format: `deleteTask INDEX` + +* Deletes the task at the specified `INDEX`. +* The index refers to the index number shown in the displayed task list. +* The index **must be a positive integer** 1, 2, 3, …​ +* The number of assigned tasks of the employees who were assigned to the deleted task will be decreased by 1. + +Examples: +* `deleteTask 2` deletes the 2nd task in the displayed task list. The number of assigned tasks of the employees who were assigned to the deleted task will be decreased by 1. +* `listTask` followed by `deleteTask 2` sets the displayed task list to show all tasks in ManageEZPZ and deletes the 2nd task in ManageEZPZ. The number of assigned tasks of the employees who were assigned to the deleted task will be decreased by 1. +* `findTask desc/slides` followed by `deleteTask 1` sets the displayed task list with the results from the findTask command and deletes the 1st task in the displayed task list. The number of assigned tasks of the employees who were assigned to the deleted task will be decreased by 1. + +### Tagging a Task to an Employee : `tagTask` + +Assigns the specified task to an employee. + +Format: `tagTask INDEX n/NAME` +* Assigns the task at the specified `INDEX` to the employee with the specified `NAME`. +* The index refers to the index number shown in the current displayed task list. +* The index **must be a positive integer** 1, 2, 3, …​ +* The employee you are tagging **must** be in the current displayed employees list. +* The name must be a valid employee **full name** in ManageEZPZ. + +Example: `tagTask 1 n/Alex Yeoh` +* `tagTask 1 n/Alex Yeoh` assigns the 1st task in the displayed task list to the employee with the name Alex Yeoh. +* `listTask` followed by `tagTask 1 n/Alex Yeoh` sets the displayed task list to show all tasks in ManageEZPZ and assigns the 1st task in ManageEZPZ to the employee with the name Alex Yeoh. +* `findTask desc/slides` followed by `tagTask 1 n/Alex Yeoh` sets the displayed task list with the results from the findTask command and assigns the 1st task in the displayed task list to the employee with the name Alex Yeoh. + +### Untagging a Task from an Employee : `untagTask` + +Deallocates the specified task from an employee. + +Format: `untagTask INDEX n/NAME` +* Deallocates the task at the specified `INDEX` from the employee with the specified `NAME`. +* The index refers to the index number shown in the current displayed task list. +* The index **must be a positive integer** 1, 2, 3, …​ +* The employee you are tagging **must** be in the current displayed employees list. +* The name must be a valid employee **full name** in ManageEZPZ. + +Example: +* `untagTask 1 n/Alex Yeoh` deallocates the 1st task in the displayed task list from the employee with the name Alex Yeoh. +* `listTask` followed by `untagTask 1 n/Alex Yeoh` sets the displayed task list to show all tasks in ManageEZPZ and deallocates the 1st task in ManageEZPZ from the employee with the name Alex Yeoh. +* `findTask desc/slides` followed by `untagTask 1 n/Alex Yeoh` sets the displayed task list with the results from the findTask command and deallocates the 1st task in the displayed task list from the employee with the name Alex Yeoh. + +### Tagging a Priority to a Task : `tagPriority` + +Assigns the specified task with a priority of either HIGH, MEDIUM, LOW or NONE. + +Format: `tagPriority INDEX priority/PRIORITY` +* Assigns the task at the specified `INDEX` with the specified priority `PRIORITY`. +* The index refers to the index number shown in the displayed task list. +* The index **must be a positive integer** 1, 2, 3, …​ +* The priority must be either `HIGH`, `MEDIUM`, `LOW`, or `NONE`. +* The priority is case-insensitive, e.g., `high`, `HIGH`, `HiGh` or `hIgH` will match as `HIGH`. +* A task with the priority of `NONE` will not have the priority reflected in the displayed task list. +* Tagging the same priority to the Task, will not change its physical state. + +Example: +* `tagPriority 1 priority/HIGH` +* `tagPriority 1 priority/HIGH` assigns the 1st task in the displayed task list with the priority of `HIGH`. +* `listTask` followed by `tagPriority 1 priority/HIGH` sets the displayed task list to show all tasks in ManageEZPZ and assigns the 1st task in ManageEZPZ with the priority of `HIGH`. +* `findTask desc/slides` followed by `tagPriority 1 priority/HIGH` sets the displayed task list with the results from the findTask command and assigns the 1st task in the displayed task list with the priority of `HIGH`. ### Clearing all entries : `clear` -Clears all entries from the address book. +Deletes all entries from the employee list and task list. Format: `clear` @@ -156,37 +412,66 @@ Format: `exit` ### Saving the data -AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. +ManageEZPZ data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. ### Editing the data file -AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file. +ManageEZPZ data are saved as a JSON file `[JAR file location]/data/ManageEZPZ.json`. Advanced users are welcome to update data directly by editing that data file. -
:exclamation: **Caution:** -If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run. -
+
-### Archiving data files `[coming in v2.0]` +:exclamation: **Caution:** +If your changes to the data file makes its format invalid, ManageEZPZ will discard all data and start with an empty data file at the next run. -_Details coming soon ..._ +
-------------------------------------------------------------------------------------------------------------------- +
## 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 AddressBook home 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 ManageEZPZ home folder. -------------------------------------------------------------------------------------------------------------------- ## Command summary -Action | Format, Examples ---------|------------------ -**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​`
e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague` -**Clear** | `clear` -**Delete** | `delete INDEX`
e.g., `delete 3` -**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…​`
e.g.,`edit 2 n/James Lee e/jameslee@example.com` -**Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake` -**List** | `list` -**Help** | `help` +### Employee Related Commands + +| Action | Format, Examples | +|---------------------|------------------------------------------------------------------------------------------------------------------| +| **Add Employee** | `addEmployee n/NAME p/PHONE_NUMBER e/EMAIL`
e.g., `addEmployee n/James Ho p/22224444 e/jamesho@example.com` | +| **List Employees** | `listEmployee` | +| **Find Employee** | `findEmployee OPTIONS`
e.g. `findEmployee n/Alex Yeoh` | +| **Edit Employee** | `editEmployee INDEX n/NAME p/PHONE_NUMBER e/EMAIL`
e.g., `edit 2 n/James Lee e/jameslee@example.com` | +| **Delete Employee** | `deleteEmployee INDEX`
e.g., `deleteEmployee 3` | + +
+ +### Task Related Commands + +| Action | Format, Examples | +|-----------------------|---------------------------------------------------------------------------------------------------------------------------------| +| **Add Todo Task** | `addTodo desc/TASK_DESCRIPTION`
e.g., `addTodo desc/read book` | +| **Add Deadline Task** | `addDeadline desc/TASK_DESCRIPTION by/DATETIME`
e.g., `addDeadline desc/return book by/2022-02-16 1800` | +| **Add Event Task** | `addEvent desc/TASK_DESCRIPTION at/DATE START_TIME END_TIME`
e.g., `addEvent desc/project meeting at/2022-02-17 1900 2000` + **Edit Task** | `editTask INDEX desc/TASK_DESCRIPTION date/DATE at/TIME`
e.g., `editTask 3 desc/homework deadline date/2022-03-15 at/1700` +| **List Tasks** | `listTasks` | +| **Find Task** | `findTask OPTIONS`
e.g.,`findTask todo/` | +| **Mark Task** | `markTask INDEX`
e.g., `markTask 2` | +| **Unmark Task** | `unmarkTask INDEX`
e.g., `unmarkTask 2` | +| **Delete Task** | `deleteTask INDEX`
e.g., `deleteTask 2` | +| **Tag Task** | `tagTask INDEX n/NAME`
e.g.,`tagTask 1 n/Alex Yeoh` | +| **Untag Task** | `untagTask INDEX n/NAME`
e.g.,`untagTask 1 n/Alex Yeoh` | +| **Tag Priority** | `tagPriority INDEX priority/PRIORITY`
e.g.,`tagPriority 1 priority/HIGH` | + +
+ +### Others + +| Action | Format | +|-----------|---------| +| **Clear** | `clear` | +| **Help** | `help` | +| **Exit** | `exit` | diff --git a/docs/_config.yml b/docs/_config.yml index 6bd245d8f4e..4409948b4df 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,4 +1,4 @@ -title: "AB-3" +title: "ManageEZPZ" theme: minima header_pages: @@ -8,7 +8,7 @@ header_pages: markdown: kramdown -repository: "se-edu/addressbook-level3" +repository: "AY2122S2-CS2103-F11-1/tp" github_icon: "images/github-icon.png" plugins: diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss index 0d3f6e80ced..f8dff39c082 100644 --- a/docs/_sass/minima/_base.scss +++ b/docs/_sass/minima/_base.scss @@ -288,7 +288,7 @@ table { text-align: center; } .site-header:before { - content: "AB-3"; + content: "ManageEZPZ"; font-size: 32px; } } diff --git a/docs/diagrams/AddSequenceDiagram.puml b/docs/diagrams/AddSequenceDiagram.puml new file mode 100644 index 00000000000..2762dd2d2c6 --- /dev/null +++ b/docs/diagrams/AddSequenceDiagram.puml @@ -0,0 +1,69 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":DeleteTaskCommandParser" as DeleteTaskCommandParser LOGIC_COLOR +participant "d:DeleteTaskCommand" as DeleteTaskCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("deleteTask 1") +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand("deleteTask 1") +activate AddressBookParser + +create DeleteTaskCommandParser +AddressBookParser -> DeleteTaskCommandParser +activate DeleteTaskCommandParser + +DeleteTaskCommandParser --> AddressBookParser +deactivate DeleteTaskCommandParser + +AddressBookParser -> DeleteTaskCommandParser : parse("deleteTask 1") +activate DeleteTaskCommandParser + +create DeleteTaskCommand +DeleteTaskCommandParser -> DeleteTaskCommand +activate DeleteTaskCommand + +DeleteTaskCommand --> DeleteTaskCommandParser : d +deactivate DeleteTaskCommand + +DeleteTaskCommandParser --> AddressBookParser : d +deactivate DeleteTaskCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +DeleteTaskCommandParser -[hidden]-> AddressBookParser +destroy DeleteTaskCommandParser + +AddressBookParser --> LogicManager : d +deactivate AddressBookParser + +LogicManager -> DeleteTaskCommand : execute() +activate DeleteTaskCommand + +DeleteTaskCommand -> Model : deleteTask(1) +activate Model + +Model --> DeleteTaskCommand +deactivate Model + +create CommandResult +DeleteTaskCommand -> CommandResult +activate CommandResult + +CommandResult --> DeleteTaskCommand +deactivate CommandResult + +DeleteTaskCommand --> LogicManager : result +deactivate DeleteTaskCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/AddTaskActivityDiagram.puml b/docs/diagrams/AddTaskActivityDiagram.puml new file mode 100644 index 00000000000..183bd639161 --- /dev/null +++ b/docs/diagrams/AddTaskActivityDiagram.puml @@ -0,0 +1,12 @@ +@startuml +start +:User executes addTodo command; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. +if (Command is Valid) + :ManageEZPZ saves the [Task]; +else ([else]) +endif +stop +@enduml diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index ef81d18c337..c420c6054e0 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -7,10 +7,10 @@ Participant ":Logic" as logic LOGIC_COLOR Participant ":Model" as model MODEL_COLOR Participant ":Storage" as storage STORAGE_COLOR -user -[USER_COLOR]> ui : "delete 1" +user -[USER_COLOR]> ui : "deleteEmployee 1" activate ui UI_COLOR -ui -[UI_COLOR]> logic : execute("delete 1") +ui -[UI_COLOR]> logic : execute("deleteEmployee 1") activate logic LOGIC_COLOR logic -[LOGIC_COLOR]> model : deletePerson(p) diff --git a/docs/diagrams/BetterModelClassDiagramUpdated.puml b/docs/diagrams/BetterModelClassDiagramUpdated.puml new file mode 100644 index 00000000000..810930b0b06 --- /dev/null +++ b/docs/diagrams/BetterModelClassDiagramUpdated.puml @@ -0,0 +1,21 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +AddressBook *-right-> "1" UniqueTaskList +AddressBook *-right-> "1" UniqueTagList +UniqueTagList -[hidden]down- UniqueTaskList +UniqueTagList -[hidden]down- UniqueTaskList + +UniqueTagList *-right-> "*" Tag +UniqueTaskList -right-> Person + +Task -up-> "* Assigned" Person + +Task -up-> Description +Todo .up.|> Task +Event .up.|> Task +Deadline .up.|> Task +@enduml diff --git a/docs/diagrams/DeleteClassDiagram.puml b/docs/diagrams/DeleteClassDiagram.puml new file mode 100644 index 00000000000..bb22f41e00d --- /dev/null +++ b/docs/diagrams/DeleteClassDiagram.puml @@ -0,0 +1,13 @@ +@startuml +start +:User executes Delete command; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if (Command is Valid) + :ManageEZPZ deletes the [Task]; +else ([else]) +endif +stop +@enduml diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml index 1dc2311b245..010388bf29b 100644 --- a/docs/diagrams/DeleteSequenceDiagram.puml +++ b/docs/diagrams/DeleteSequenceDiagram.puml @@ -4,8 +4,8 @@ box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR -participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR -participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR +participant ":DeleteEmployeeCommandParser" as DeleteEmployeeCommandParser LOGIC_COLOR +participant "d:DeleteEmployeeCommand" as DeleteEmployeeCommand LOGIC_COLOR participant ":CommandResult" as CommandResult LOGIC_COLOR end box @@ -13,56 +13,56 @@ box Model MODEL_COLOR_T1 participant ":Model" as Model MODEL_COLOR end box -[-> LogicManager : execute("delete 1") +[-> LogicManager : execute("deleteEmployee 1") activate LogicManager -LogicManager -> AddressBookParser : parseCommand("delete 1") +LogicManager -> AddressBookParser : parseCommand("deleteEmployee 1") activate AddressBookParser -create DeleteCommandParser -AddressBookParser -> DeleteCommandParser -activate DeleteCommandParser +create DeleteEmployeeCommandParser +AddressBookParser -> DeleteEmployeeCommandParser +activate DeleteEmployeeCommandParser -DeleteCommandParser --> AddressBookParser -deactivate DeleteCommandParser +DeleteEmployeeCommandParser --> AddressBookParser +deactivate DeleteEmployeeCommandParser -AddressBookParser -> DeleteCommandParser : parse("1") -activate DeleteCommandParser +AddressBookParser -> DeleteEmployeeCommandParser : parse("1") +activate DeleteEmployeeCommandParser -create DeleteCommand -DeleteCommandParser -> DeleteCommand -activate DeleteCommand +create DeleteEmployeeCommand +DeleteEmployeeCommandParser -> DeleteEmployeeCommand +activate DeleteEmployeeCommand -DeleteCommand --> DeleteCommandParser : d -deactivate DeleteCommand +DeleteEmployeeCommand --> DeleteEmployeeCommandParser : d +deactivate DeleteEmployeeCommand -DeleteCommandParser --> AddressBookParser : d -deactivate DeleteCommandParser +DeleteEmployeeCommandParser --> AddressBookParser : d +deactivate DeleteEmployeeCommandParser 'Hidden arrow to position the destroy marker below the end of the activation bar. -DeleteCommandParser -[hidden]-> AddressBookParser -destroy DeleteCommandParser +DeleteEmployeeCommandParser -[hidden]-> AddressBookParser +destroy DeleteEmployeeCommandParser AddressBookParser --> LogicManager : d deactivate AddressBookParser -LogicManager -> DeleteCommand : execute() -activate DeleteCommand +LogicManager -> DeleteEmployeeCommand : execute() +activate DeleteEmployeeCommand -DeleteCommand -> Model : deletePerson(1) +DeleteEmployeeCommand -> Model : deletePerson(1) activate Model -Model --> DeleteCommand +Model --> DeleteEmployeeCommand deactivate Model create CommandResult -DeleteCommand -> CommandResult +DeleteEmployeeCommand -> CommandResult activate CommandResult -CommandResult --> DeleteCommand +CommandResult --> DeleteEmployeeCommand deactivate CommandResult -DeleteCommand --> LogicManager : result -deactivate DeleteCommand +DeleteEmployeeCommand --> LogicManager : result +deactivate DeleteEmployeeCommand [<--LogicManager deactivate LogicManager diff --git a/docs/diagrams/FindTaskClassDiagram.puml b/docs/diagrams/FindTaskClassDiagram.puml new file mode 100644 index 00000000000..14fb0542334 --- /dev/null +++ b/docs/diagrams/FindTaskClassDiagram.puml @@ -0,0 +1,13 @@ +@startuml +start +:User executes findTask/findEmployee command; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if (Attributes entered are Valid) + :ManageEZPZ finds [Tasks/Employees] that contains the stated attributes; +else ([else]) +endif +stop +@enduml diff --git a/docs/diagrams/FindTaskCommandSequenceDiagram.puml b/docs/diagrams/FindTaskCommandSequenceDiagram.puml new file mode 100644 index 00000000000..7a3894e586f --- /dev/null +++ b/docs/diagrams/FindTaskCommandSequenceDiagram.puml @@ -0,0 +1,60 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":FindTaskCommandParser" as FindTaskCommandParser LOGIC_COLOR +participant ":FindTaskCommand" as FindTaskCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("findTask todo/") +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand("findTask todo/") +activate AddressBookParser + +create FindTaskCommandParser +AddressBookParser -> FindTaskCommandParser +activate FindTaskCommandParser +FindTaskCommandParser --> AddressBookParser : :FindTaskCommandParser +deactivate FindTaskCommandParser + +AddressBookParser -> FindTaskCommandParser : parse(" todo/") +activate FindTaskCommandParser + +create FindTaskCommand +FindTaskCommandParser -> FindTaskCommand : FindTaskCommand() +activate FindTaskCommand +FindTaskCommand -> FindTaskCommandParser : :FindTaskCommand +deactivate FindTaskCommand + +FindTaskCommandParser --> AddressBookParser : :FindTaskCommand +deactivate FindTaskCommandParser + +AddressBookParser --> LogicManager : :FindTaskCommand +deactivate AddressBookParser + +LogicManager -> FindTaskCommand : execute() +activate FindTaskCommand + +FindTaskCommand -> Model : updateFilteredTaskList() +activate Model + +Model --> FindTaskCommand +deactivate Model + +create CommandResult +FindTaskCommand -> CommandResult +activate CommandResult + +CommandResult --> FindTaskCommand : :CommandResult +deactivate CommandResult + +FindTaskCommand --> LogicManager : :CommandResult +@enduml diff --git a/docs/diagrams/MarkClassDiagram.puml b/docs/diagrams/MarkClassDiagram.puml new file mode 100644 index 00000000000..f11e3ed1886 --- /dev/null +++ b/docs/diagrams/MarkClassDiagram.puml @@ -0,0 +1,13 @@ +@startuml +start +:User executes Mark command; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if (Command is Valid) + :ManageEZPZ marks the [Task] as done; +else ([else]) +endif +stop +@enduml diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index 4439108973a..40357a5a194 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -14,19 +14,18 @@ Class UserPrefs Class UniquePersonList Class Person -Class Address Class Email Class Name Class Phone -Class Tag +Package TaskModel { +} } Class HiddenOutside #FFFFFF HiddenOutside ..> Model AddressBook .up.|> ReadOnlyAddressBook - ModelManager .up.|> Model Model .right.> ReadOnlyUserPrefs Model .left.> ReadOnlyAddressBook @@ -34,17 +33,12 @@ ModelManager -left-> "1" AddressBook ModelManager -right-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs -AddressBook *--> "1" UniquePersonList UniquePersonList --> "~* all" Person +AddressBook *--> "1" UniquePersonList Person *--> Name Person *--> Phone Person *--> Email -Person *--> Address -Person *--> "*" Tag - -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email ModelManager -->"~* filtered" Person +ModelManager --> TaskModel @enduml diff --git a/docs/diagrams/ModelTaskClassDiagram.puml b/docs/diagrams/ModelTaskClassDiagram.puml new file mode 100644 index 00000000000..bbd7a76bafa --- /dev/null +++ b/docs/diagrams/ModelTaskClassDiagram.puml @@ -0,0 +1,37 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +Package TaskModel <>{ +Class Task +Class Todo +Class Event +Class Deadline +Class Date +Class Time +Class Description +Class UniqueTaskList +Class "<>\nPriority\n----\nHigh\nMedium\nLow\nNone" as Priority + +} + +UniqueTaskList --> "~* all" Task +AddressBook *--> "1" UniqueTaskList +Task *-> Priority +Task *-> Description +Todo .up.|> Task +Event .up.|> Task +Deadline .up.|> Task +Event *--> "2" Time +Event *--> Date +Deadline *--> Date +Deadline *--> Time +Todo *--> Description +Event *--> Description +Deadline *--> Description + +ModelManager -->"~* filtered" Task +Task -->"~* assigned" Person +@enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 760305e0e58..625b05043dc 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -19,7 +19,7 @@ Class "<>\nAddressBookStorage" as AddressBookStorage Class JsonAddressBookStorage Class JsonSerializableAddressBook Class JsonAdaptedPerson -Class JsonAdaptedTag +Class JsonAdaptedTask } } @@ -38,6 +38,6 @@ JsonUserPrefsStorage .up.|> UserPrefsStorage JsonAddressBookStorage .up.|> AddressBookStorage JsonAddressBookStorage ..> JsonSerializableAddressBook JsonSerializableAddressBook --> "*" JsonAdaptedPerson -JsonAdaptedPerson --> "*" JsonAdaptedTag +JsonSerializableAddressBook --> "*" JsonAdaptedTask @enduml diff --git a/docs/diagrams/TagTaskActivityDiagram.puml b/docs/diagrams/TagTaskActivityDiagram.puml new file mode 100644 index 00000000000..0442fa7efe9 --- /dev/null +++ b/docs/diagrams/TagTaskActivityDiagram.puml @@ -0,0 +1,12 @@ +@startuml +start +:User executes tagTask command; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. +if (Command is Valid) + :ManageEZPZ assigns [Person] to [Task]; +else ([else]) +endif +stop +@enduml diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 95473d5aa19..169213adb03 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -13,6 +13,8 @@ Class HelpWindow Class ResultDisplay Class PersonListPanel Class PersonCard +Class TaskListPanel +Class TaskCard Class StatusBarFooter Class CommandBox } @@ -30,13 +32,15 @@ HiddenOutside ..> Ui UiManager .left.|> Ui UiManager -down-> "1" MainWindow -MainWindow *-down-> "1" CommandBox +MainWindow *-down-> "1" CommandBox MainWindow *-down-> "1" ResultDisplay MainWindow *-down-> "1" PersonListPanel +MainWindow *-down-> "1" TaskListPanel MainWindow *-down-> "1" StatusBarFooter MainWindow --> "0..1" HelpWindow PersonListPanel -down-> "*" PersonCard +TaskListPanel -down-> "*" TaskCard MainWindow -left-|> UiPart @@ -44,10 +48,13 @@ ResultDisplay --|> UiPart CommandBox --|> UiPart PersonListPanel --|> UiPart PersonCard --|> UiPart +TaskListPanel --|> UiPart +TaskCard --|> UiPart StatusBarFooter --|> UiPart HelpWindow --|> UiPart PersonCard ..> Model +TaskCard ..> Model UiManager -right-> Logic MainWindow -left-> Logic diff --git a/docs/diagrams/UnmarkClassDiagram.puml b/docs/diagrams/UnmarkClassDiagram.puml new file mode 100644 index 00000000000..6e06d746b2a --- /dev/null +++ b/docs/diagrams/UnmarkClassDiagram.puml @@ -0,0 +1,13 @@ +@startuml +start +:User executes Unmark command; + +'Since the beta syntax does not support placing the condition outside the +'diamond we place it as the true branch instead. + +if (Command is Valid) + :ManageEZPZ unmarks the [Task], which changes the status back to not done; +else ([else]) +endif +stop +@enduml diff --git a/docs/images/AddSeqDiagram.png b/docs/images/AddSeqDiagram.png new file mode 100644 index 00000000000..c009a63104c Binary files /dev/null and b/docs/images/AddSeqDiagram.png differ diff --git a/docs/images/AddSequenceDiagram.png b/docs/images/AddSequenceDiagram.png new file mode 100644 index 00000000000..40ec3842a1a Binary files /dev/null and b/docs/images/AddSequenceDiagram.png differ diff --git a/docs/images/AddTaskActivityDiagram.png b/docs/images/AddTaskActivityDiagram.png new file mode 100644 index 00000000000..49c344d8163 Binary files /dev/null and b/docs/images/AddTaskActivityDiagram.png differ diff --git a/docs/images/AddTodo.png b/docs/images/AddTodo.png new file mode 100644 index 00000000000..89aaad61f3a Binary files /dev/null and b/docs/images/AddTodo.png differ diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 2f1346869d0..068bd1f2a66 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/BetterModelClassDiagramUpdated.png b/docs/images/BetterModelClassDiagramUpdated.png new file mode 100644 index 00000000000..5d8e16eef3a Binary files /dev/null and b/docs/images/BetterModelClassDiagramUpdated.png differ diff --git a/docs/images/DeleteClassDiagram.png b/docs/images/DeleteClassDiagram.png new file mode 100644 index 00000000000..9247a1136da Binary files /dev/null and b/docs/images/DeleteClassDiagram.png differ diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png index fa327b39618..4ecd6e8d5de 100644 Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ diff --git a/docs/images/DeleteTask.png b/docs/images/DeleteTask.png new file mode 100644 index 00000000000..d855157e3cf Binary files /dev/null and b/docs/images/DeleteTask.png differ diff --git a/docs/images/EditTaskDesc.PNG b/docs/images/EditTaskDesc.PNG new file mode 100644 index 00000000000..a9c54116560 Binary files /dev/null and b/docs/images/EditTaskDesc.PNG differ diff --git a/docs/images/EditTaskSequenceDiagram.png b/docs/images/EditTaskSequenceDiagram.png new file mode 100644 index 00000000000..11c9229b6df Binary files /dev/null and b/docs/images/EditTaskSequenceDiagram.png differ diff --git a/docs/images/FindTaskClassDiagram.png b/docs/images/FindTaskClassDiagram.png new file mode 100644 index 00000000000..fe75ccffb4a Binary files /dev/null and b/docs/images/FindTaskClassDiagram.png differ diff --git a/docs/images/FindTaskCommand.png b/docs/images/FindTaskCommand.png new file mode 100644 index 00000000000..6dafd5591d3 Binary files /dev/null and b/docs/images/FindTaskCommand.png differ diff --git a/docs/images/FindTaskCommandSequenceDiagram.png b/docs/images/FindTaskCommandSequenceDiagram.png new file mode 100644 index 00000000000..22baa93e7c0 Binary files /dev/null and b/docs/images/FindTaskCommandSequenceDiagram.png differ diff --git a/docs/images/MarkClassDiagram.png b/docs/images/MarkClassDiagram.png new file mode 100644 index 00000000000..2740b483b57 Binary files /dev/null and b/docs/images/MarkClassDiagram.png differ diff --git a/docs/images/MarkTask.png b/docs/images/MarkTask.png new file mode 100644 index 00000000000..e866b944341 Binary files /dev/null and b/docs/images/MarkTask.png differ diff --git a/docs/images/ModelClassDiagramUpdated.png b/docs/images/ModelClassDiagramUpdated.png new file mode 100644 index 00000000000..c2d76f85383 Binary files /dev/null and b/docs/images/ModelClassDiagramUpdated.png differ diff --git a/docs/images/ModelTaskClassDiagram.png b/docs/images/ModelTaskClassDiagram.png new file mode 100644 index 00000000000..30ad4c9532e Binary files /dev/null and b/docs/images/ModelTaskClassDiagram.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index 2533a5c1af0..9d68fddfb14 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/TagTask.png b/docs/images/TagTask.png new file mode 100644 index 00000000000..d4edd8cc759 Binary files /dev/null and b/docs/images/TagTask.png differ diff --git a/docs/images/TagTaskActivityDiagram.png b/docs/images/TagTaskActivityDiagram.png new file mode 100644 index 00000000000..9bf347f3610 Binary files /dev/null and b/docs/images/TagTaskActivityDiagram.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..b25ea996661 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 785e04dbab4..d4aa9cea14b 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/UnmarkClassDiagram.png b/docs/images/UnmarkClassDiagram.png new file mode 100644 index 00000000000..a71f422c345 Binary files /dev/null and b/docs/images/UnmarkClassDiagram.png differ diff --git a/docs/images/UnmarkTask.png b/docs/images/UnmarkTask.png new file mode 100644 index 00000000000..c3112788615 Binary files /dev/null and b/docs/images/UnmarkTask.png differ diff --git a/docs/images/aaron-ljx.png b/docs/images/aaron-ljx.png new file mode 100644 index 00000000000..a4b74b7a40b Binary files /dev/null and b/docs/images/aaron-ljx.png differ diff --git a/docs/images/alfredkohhh.png b/docs/images/alfredkohhh.png new file mode 100644 index 00000000000..a6f7e307c55 Binary files /dev/null and b/docs/images/alfredkohhh.png differ diff --git a/docs/images/chanweijie.png b/docs/images/chanweijie.png new file mode 100644 index 00000000000..e3174f91317 Binary files /dev/null and b/docs/images/chanweijie.png differ diff --git a/docs/images/dannytayjy.png b/docs/images/dannytayjy.png new file mode 100644 index 00000000000..60d14a7cf19 Binary files /dev/null and b/docs/images/dannytayjy.png differ diff --git a/docs/images/denniszedead.png b/docs/images/denniszedead.png new file mode 100644 index 00000000000..c7298c45222 Binary files /dev/null and b/docs/images/denniszedead.png differ diff --git a/docs/images/email_icon.png b/docs/images/email_icon.png new file mode 100644 index 00000000000..fbcc54c9b44 Binary files /dev/null and b/docs/images/email_icon.png differ diff --git a/docs/images/employee_icon.png b/docs/images/employee_icon.png new file mode 100644 index 00000000000..c109dd85302 Binary files /dev/null and b/docs/images/employee_icon.png differ diff --git a/docs/images/helpMessage_new.png b/docs/images/helpMessage_new.png new file mode 100644 index 00000000000..542f639bfc2 Binary files /dev/null and b/docs/images/helpMessage_new.png differ diff --git a/docs/images/phone_icon.png b/docs/images/phone_icon.png new file mode 100644 index 00000000000..cf419e7a195 Binary files /dev/null and b/docs/images/phone_icon.png differ diff --git a/docs/images/priorities_high.png b/docs/images/priorities_high.png new file mode 100644 index 00000000000..25f6325cfcd Binary files /dev/null and b/docs/images/priorities_high.png differ diff --git a/docs/images/priorities_low.png b/docs/images/priorities_low.png new file mode 100644 index 00000000000..ef947e38e6d Binary files /dev/null and b/docs/images/priorities_low.png differ diff --git a/docs/images/priorities_medium.png b/docs/images/priorities_medium.png new file mode 100644 index 00000000000..59d96906ea8 Binary files /dev/null and b/docs/images/priorities_medium.png differ diff --git a/docs/images/task_icon.png b/docs/images/task_icon.png new file mode 100644 index 00000000000..21ecee071ea Binary files /dev/null and b/docs/images/task_icon.png differ diff --git a/docs/index.md b/docs/index.md index 7601dbaad0d..51f0efb8d69 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,17 @@ --- layout: page -title: AddressBook Level-3 +title: ManageEZPZ --- -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) -[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3) +[![CI Status](https://github.com/AY2122S2-CS2103-F11-1/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S2-CS2103-F11-1/tp/actions) +[![codecov](https://codecov.io/gh/AY2122S2-CS2103-F11-1/tp/branch/master/graph/badge.svg?token=ILZDIFELY7)](https://codecov.io/gh/AY2122S2-CS2103-F11-1/tp) ![Ui](images/Ui.png) -**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). +**ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). -* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). -* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. +* If you are interested in using ManageEZPZ, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). +* If you are interested about developing ManageEZPZ, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. **Acknowledgements** diff --git a/docs/team/aaron-ljx.md b/docs/team/aaron-ljx.md new file mode 100644 index 00000000000..d0baa44fda6 --- /dev/null +++ b/docs/team/aaron-ljx.md @@ -0,0 +1,42 @@ +Loke Jin Xue Aaron's Project Portfolio Page +--- + +### Project: ManageEZPZ + +ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java. + +Given below are my contributions to the project. + +* **New Feature**: + * **Edit Task** ([#122](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/122)) + * User is able to freely edit different kind of tasks (Todo, Deadline, Event) + * For example, a user can just edit the description of a Deadline task + or update both description and date at the same time. + * **Add Task (Deadline, Event)** ([#73](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/73)) + * User is able to add Deadline and Event task to their list. + + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=aaron-ljx&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + + +* **Project management**: + * To be updated soon + + +* **Enhancements**: + * Extended Task base class to implement Event and Deadline classes ([#73](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/73)) + + +* **Documentation**: + * User Guide: + * Wrote the Edit Task portion ([#171](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/171)) + * Developer Guide: + * Elaborated on how the Edit Task function worked with accompanying image ([#128](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/128)) + + +* **Community**: + * Reported bugs and suggestions for other team in the same CS2103/T class : [PE Dry Run](https://github.com/aaron-ljx/ped/issues) + + +* **Tools**: + * IntelliJ IDEA diff --git a/docs/team/alfredkohhh.md b/docs/team/alfredkohhh.md new file mode 100644 index 00000000000..9085fc3e69d --- /dev/null +++ b/docs/team/alfredkohhh.md @@ -0,0 +1,62 @@ +--- +layout: page +title: Alfred's Project Portfolio Page +--- + +### Project: ManageEZPZ + +ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java. +Given below are my contributions to the project. + +* **New Feature**: + * Implemented JsonAdaptedTask. In which, handled, maintained and enhanced all Storage related matters for ManageEZPZ. + * What it does: The creation of `JsonAdaptedTask` allows ManageEZPZ to have a centralised area to handle all Task-Storage matters. + * Completed full implementation of add Todo Task, Command, Logic, Storage as a full template for team to follow. [#72](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/72) + * Implemented Storage functionality for Mark and Unmark Tasks. [#83](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/83) + * Completed full implementation of Tag Task Command, Logic, Storage. [#108](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/108) + * Completed full implementation of Untag Task Command, Logic, Storage. [#111](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/111) + * Completed full implementation of Tag Priority Command, Logic, Storage. [#131](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/131) + * Implemented tracking number of Tasks assigned to Employee [#146](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/146) + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=alfredkohhh&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other) + +* **Project management**: + * Ensured the team's completion of weekly deliverables (Handled with Wei Jie) + + +* **Enhancements to existing features**: + * Refactored existing add command to addEmployee command. [#67](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/67) + * Fix and standardise all AddTask commands, added 'type' field for Task model. [#75](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/75) + * Justification: By having a 'type' field, it allows for better identification and loading of Tasks. + * Enhanced storage to handle different fields for the different types of Tasks. [#77](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/77) + * Justification: With the different types of Task having different fields, it is important for the JsonAdaptedTask to handle and load the different fields of each Task. + * Added error-prevention for AddDeadlineTaskParser, AddEventTaskCommandParser for the length of arguments. [#94](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/94) + +
+ + * Enhanced Logic for DeleteEmployee, deleting an Employee will untag all tasks that employee is assigned to, then proceeds to delete. [#141](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/141) + * Justification: Deleting an employee should also update all associations related to that employee. + * Supported Storage by adding Defensive Programming logic to counter Json being modified. [#249](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/249) + * Justification: In cases where the Number of Tasks / other fields are being edited, we should check if the loaded details matches with our current state. + +* **Documentation**: + * Developer Guide: + * Added Use-Cases. [#22](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/22), + [#97](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/97) + * Polished Storage description, added Storage Class-Diagram. [#113](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/113) + * Update AddTask and TagTask descriptions. [#130](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/130) + + * User Guide: + * Rectify and polished UG based on v1.3 PE-D Issues. [#248](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/248) + * Added tagTask, untagTask, tagPriority. [#162](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/162) + +* **Community**: + * PR Reviewed & Merged: [#64](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/64), + [#73](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/73), + [#87](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/87), + [#89](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/89), + [#96](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/96), + [#107](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/107), + [#123](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/123), + [#145](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/145) + diff --git a/docs/team/chanweijie.md b/docs/team/chanweijie.md new file mode 100644 index 00000000000..9ef2a364d71 --- /dev/null +++ b/docs/team/chanweijie.md @@ -0,0 +1,57 @@ +--- +layout: page +title: Chan Wei Jie's Project Portfolio Page +--- + +### Project: ManageEZPZ + +ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java. + +Given below are my contributions to the project. + +* **Enhancement**: Creation of the model component for `Task` as a baseline for the use by other teammates. [#64](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/64), [#81](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/81) + * What it does : The creation of the `Task` component allows for smoother creation of the different types of Task related commands. + * Justification : This enhancement is important as the different type of Task related command such as adding, deleting, editing and even finding. All relies on the methods created in the `Task` model. + * Highlights : This enhancement required me to constantly update the methods that are required by my teammates as the methods in the `Task` Model changes as more commands are being added. As well as the importance of abstraction principles in the implementation of the `Task` class. + + +* **Enhancement**: Creation of Enum class `Priority`. + * What it does : The Enum class `Priority` allows the different types of Task to be assigned with a Priority. [#145](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/145) + * Justification : This enhancement is important as the tagPriority command relies on Tasks having priorities. + * Highlights : Creating a separate enum class for `Priority` makes the `Task` class more readable as opposed to clustering them together. + + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=chanweijie&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + + +* **Project management**: + * Managed milestones `v1.1` - `v1.4` on GitHub. + * Ensured the team's completion of weekly deliverables and its deadlines. + * Managed releases `v1.2` - `v1.4` on GitHub. + * Delegated team members what functionalities each of us had to implement to prevent any conflict and provide a better workflow. + +
+ +* **Enhancements to existing features**: + * Changed the Employee class to not have `address` & `tag` fields. [#62](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/62) + * Removed the `address` and `tagged` fields in the affected json storage files. [#70](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/70) + * Updating `Description` to only validate empty descriptions. [#104](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/104) + * Updating `Task` class to be abstract so that it can be inherited by its sub-classes like `todo`/`event`/`deadline`. [#156](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/156) + * Refactored the `editcommand` to `editEmployeeCommand`. [#167](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/167) + + +* **Documentation**: + * User Guide: + * Added Commands to be implemented in v1.2. [#21](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/21) + * Added back the `delete` command for Person but renamed it as `deleteEmployee`. [#103](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/103) + * Developer Guide : + * Added implementation details of the `Task` Model, including two class diagrams. [#120](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/120), [#127](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/127) + * Added appendix instructions for manual testing & appendix for Effort. [#286](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/286) + +* **Community**: + * Setting up the GitHub team org & repo. + * Necessary general code enhancements such as renaming the product: [#175](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/175), [#176](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/176) + * PRs reviewed (with non-trivial review comments): [#73](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/73), [#30](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/30) + * Reported bugs and suggestions for other teams: [Dry run PE](https://github.com/ChanWeiJie/ped/issues) + + diff --git a/docs/team/dannytayjy.md b/docs/team/dannytayjy.md new file mode 100644 index 00000000000..a990f92ac58 --- /dev/null +++ b/docs/team/dannytayjy.md @@ -0,0 +1,101 @@ +--- +layout: page +title: Tay Jun Yang's Project Portfolio Page +--- + +## Project: ManageEZPZ + +ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java. + +Given below are my contributions to the project. + +* **New Features:** + * Implemented `markTask` feature, which marks the task identified by the index number used in the displayed task list as done. ([#87](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/87), [#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170)) + * Implemented `unmarkTask` feature, which unmarks the task identified by the index number used in the displayed task list, which changes the status back to not done. ([#87](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/87), [#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170)) + * Implemented `deleteTask` feature, which deletes the task identified by the index number used in the displayed task list. The number of assigned tasks of the employees who were assigned to the deleted task will then be decreased by 1. ([#89](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/89), [#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170), [#259](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/259)) + * Implemented Copying Employee Details to Computer Clipboard feature, which enables the user to right-click on an employee to copy the full name, phone number and email to Computer Clipboard. ([#181](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/181)) + * Justification: This feature allows the user to tag a task to an employee or untag a task from an employee easily by pasting the copied full name of the employee into the command text box. + + +* **Enhancements to Graphical User Interface (GUI) of Main Window:** ([#123](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/123), [#142](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/142), [#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170), [#181](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/181), [#247](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/247), [#326](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/326)) + * Tweaked the GUI to display the employee list and task list. + * In employee list, details of each employee (`name`, `phone`, `email`, `numOfTasks`) are listed. + * In task list, details of each task (`description`, `type`, `assignees`, `priority`, `isDone`) are listed. + * Justification: + * This enhancement is important as all other features implemented by my teammates must be reflected correctly in the employee list and task list. + * Highlights: + * This enhancement requires me to research on JavaFX extensively as I need to understand JavaFx properties and build layouts in fxml code with the help of the Scene Builder software. I will also need to have knowledge on CSS as CSS is used to set the style and alignment of JavaFx containers and controls. + * This enhancement ensures that the employee list and task list displayed in the GUI are updated synchronously whenever any changes are made to the data. + * This enhancement ensures that all features implemented by my teammates are working as expected. + + +* **Enhancements to Existing Features:** + * Enhanced the `editEmployee` feature, which is refactored from the `edit` feature of AddressBook-Level3. + * Justification: The `editEmployee` feature edits the details of the employee identified by the index number used in the displayed employee list. All tasks that are assigned to the edited employee is then updated to reflect the new changes of the employee. ([#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170), [#179](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/179)) + * Enhanced the `deleteEmployee` feature, which is refactored from the `delete` feature of AddressBook-Level3. + * Justification: The `deleteEmployee` feature deletes the employee identified by the index number used in the displayed employee list. All tasks that are assigned to the deleted employee is then updated to remove the employee from the respective tasks. ([#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170), [#182](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/182)) + * Updated the GUI of the Help Window to replace the user guide URL and showcase the feature of copying employee details to Computer Clipboard. ([#247](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/247)) + + +* **Enhancements to New Features:** + * Tweaked the `tagTask` feature implemented by team member [Alfred Koh](https://ay2122s2-cs2103-f11-1.github.io/tp/team/alfredkohhh.html). ([#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170)) + * Ensured that the GUI is updated synchronously to show that + * the task is assigned to the employee in the displayed employee list and the number of assigned tasks of the employee is increased by 1. + * the employee's full name is added to the assignees of the task in the displayed task list. + * Tweaked the `untagTask` feature implemented by team member [Alfred Koh](https://ay2122s2-cs2103-f11-1.github.io/tp/team/alfredkohhh.html). ([#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170)) + * Ensured that the GUI is updated synchronously to show that + * the task is deallocated from the employee in the displayed employee list and the number of assigned tasks of the employee is decreased by 1. + * the employee's full name is removed from the assignees of the task in the displayed task list. + * Tweaked the `tagPriority` feature implemented by team member [Alfred Koh](https://ay2122s2-cs2103-f11-1.github.io/tp/team/alfredkohhh.html). ([#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170)) + * Ensured that the GUI is updated synchronously to show that the task is assigned with the specified `priority`. + * Tweaked the `editTask` feature implemented by team member [Aaron Loke](https://ay2122s2-cs2103-f11-1.github.io/tp/team/aaron-ljx.html). ([#179](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/179), [#182](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/182), [#185](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/185)) + * Handled bugs such as IndexOutOfBounds for invalid task index of the displayed task list. + * Ensured that `type`, `assignees`, `priority` and `isDone` remain unchanged and the original values are not discarded after editing the task. + * Ensured that exception messages are thrown correctly and appropriately. + * Ensured that the GUI is updated synchronously to show that the task details are updated. + * Guided team member Aaron on the approach of resolving the bugs so that the advertised behaviour in the UG will be consistent with the actual behaviour ([#256](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/256)). + + +* **Enhancements to Validation Checks and Error Messages:** ([#179](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/179), [#185](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/185), [#247](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/247), [#259](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/259)) + * Ensured that all validation checks are handled properly. + * Ensured that all error messages shown to the user upon executing the wrong commands are correct and understandable, so that the user can recover from any errors and continue using the application. + + +* **Icons for GUI:** + * Created icons. ([#142](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/142), [#181](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/181)) +
+ * Modified Task icon created by feen (Flaticon) to fill up colours and change stroke colour. ([#142](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/142)) +
+ + +* **Code Contributed:** [RepoSense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=dannytayjy&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + + +* **Project Management:** + * Released v1.3.3 and v1.3.4 on GitHub after bug fixes. + * Assisted in merging PRs of implementations done by other teammates. + + +* **Documentation:** + * User Guide: + * Added full details for the features `editEmployee`, `deleteEmployee`, `markTask`, `unmarkTask` and `deleteTask`. ([#169](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/169), [#259](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/259)) + * Polished the details and examples for the features `tagTask`, `untagTask` and `tagPriority`. ([#169](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/169)) + * Standardized the formatting of all commands and update some missing details in other commands. ([#169](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/169)) + * Updated the table formatting for Command Summary. ([#169](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/169)) + * Developer Guide: + * Added Non-Functional Requirements and Glossary details. ([#20](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/20)) + * Added implementation details of the `UI` component for `TaskListPanel` and `TaskListCard`. ([#129](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/129)) + * Added implementation details of the `Logic` component for `deleteTask`, `markTask` and `unmarkTask` features, including the class diagrams and screenshots of the application executing the feature. ([#129](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/129), [#292](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/292)) + + +* **Community:** + * Refactored project's Java package to manageezpz : [#60](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/60) + * Updated the user guide URL in the Help Window : [#247](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/247) + * Reviewed PRs with non-trivial review comments : [#108](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/108), [#145](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/145), [#156](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/156), [#161](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/161), [#257](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/257) + * Reported bugs and suggestions for other team in the same CS2103/T class : [PE Dry Run](https://github.com/dannytayjy/ped/issues) + + +* **Tools:** + * IntelliJ IDEA + * JavaFX Scene Builder + * Adobe Photoshop diff --git a/docs/team/denniszedead.md b/docs/team/denniszedead.md new file mode 100644 index 00000000000..90a6c123e7d --- /dev/null +++ b/docs/team/denniszedead.md @@ -0,0 +1,62 @@ +--- +layout: page +title: Ng Wen Hao Dennis's Project Portfolio Page +--- + +### Project: ManageEZPZ + +ManageEZPZ is a desktop application that allows managers or supervisors to manage employees and assign tasks to them. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java. + +Given below are my contributions to the project. + +#### Enhancement implemented +`findEmployee` command: +* Change from `find` command to `findEmployee` command to reflect and differentiate this find command to find all employees. +* Create a new predicate `PersonMultiplePredicate` to filter out employees based on multiple properties entered by user. +* Unit test for the new `findEmployee` command include: + * `findEmployeeCommandParser` to check on different user inputs. + * `findEmployeeCommand` to show different outcome on the `finteredPersonList` for different user inputs. + * `PersonMultiplePredicate` to ensure that only employees that satisfy the options given to the users return true. + +`listEmployee` command: +* Only change the command from `list` to `listEmployees` to reflect on listing down all the employees. +* Functionalities remain the same from AB3. + +
+ +`findTask` command: +* To allow users to find tasks which was a new model added into our project. +* Allowed users to search tasks using multiple properties of a task. +* Created a new predicate `TaskMultiplePredicate` to filter out tasks based on multiple properties entered by users +* Added unit testing for: + * `findTaskCommandParser` to check on different user inputs. + * `findTaskCommand` to show different outcome on the `finteredTaskList` for different user inputs. + * `TaskMultiplePredicate` to ensure that only tasks that satisfy the options given to the users return true. + +`listTask` command: +* List down all the tasks in the filteredList. +* Unit test for `listTask` to use the following test cases: + * When the current task list is already filtered. + * When the user task list already shows all task in the task list. + +#### Code contributed +[Repo sense link](https://nus-cs2103-ay2122s2.github.io/tp-dashboard/?search=denniszedead&breakdown=true&sort=groupTitle&sortWithin=title&since=2022-02-18&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + +#### PR Reviewed +* [#72](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/72), +[#141](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/141), +[#142](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/142), +[#146](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/146), +[#170](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/170), +[#241](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/241), +[#242](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/242), +[#246](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/246), +[#247](https://github.com/AY2122S2-CS2103-F11-1/tp/pull/247) + +#### Forum contribution +* [Asked on whether ternary operators improves code quality](https://github.com/nus-cs2103-AY2122S2/forum/issues/131) + +#### Contributions to team based task +* Created a team shared document +* [Create our team PR into the module repo](https://github.com/nus-cs2103-AY2122S2/tp/pull/62) +* Submitted tp UG draft into LumiNUS. diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index 773a07794e2..00000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: page -title: John Doe's Project Portfolio Page ---- - -### Project: AddressBook Level 3 - -AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. - -Given below are my contributions to the project. - -* **New Feature**: Added the ability to undo/redo previous commands. - * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. - * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. - * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. - * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}* - -* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys. - -* **Code contributed**: [RepoSense link]() - -* **Project management**: - * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub - -* **Enhancements to existing features**: - * Updated the GUI color scheme (Pull requests [\#33](), [\#34]()) - * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]()) - -* **Documentation**: - * User Guide: - * Added documentation for the features `delete` and `find` [\#72]() - * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]() - * Developer Guide: - * Added implementation details of the `delete` feature. - -* **Community**: - * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() - * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) - * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) - * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]()) - -* **Tools**: - * Integrated a third party library (Natty) to the project ([\#42]()) - * Integrated a new Github plugin (CircleCI) to the team repo - -* _{you can add/remove categories in the list above}_ diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md index 880c701042f..a8b5f54fd57 100644 --- a/docs/tutorials/AddRemark.md +++ b/docs/tutorials/AddRemark.md @@ -25,7 +25,7 @@ For now, let’s keep `RemarkCommand` as simple as possible and print some outpu ``` java package seedu.address.logic.commands; -import seedu.address.model.Model; +import manageezpz.model.Model; /** * Changes the remark of an existing person in the address book. @@ -91,7 +91,7 @@ Let’s change `RemarkCommand` to parse input from the user. We start by modifying the constructor of `RemarkCommand` to accept an `Index` and a `String`. While we are at it, let’s change the error message to echo the values. While this is not a replacement for tests, it is an obvious way to tell if our code is functioning as intended. ``` java -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; //... public class RemarkCommand extends Command { //... @@ -242,7 +242,7 @@ Let’s change `RemarkCommand` and `RemarkCommandParser` to use the new `Remark` Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each person. -Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688). +Simply add the following to [`manageezpz.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688). **`PersonCard.java`:** diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md index f29169bc924..f778cae5db5 100644 --- a/docs/tutorials/RemovingFields.md +++ b/docs/tutorials/RemovingFields.md @@ -28,7 +28,7 @@ IntelliJ IDEA provides a refactoring tool that can identify *most* parts of a re ### Assisted refactoring -The `address` field in `Person` is actually an instance of the `seedu.address.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu. +The `address` field in `Person` is actually an instance of the `manageezpz.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu. * :bulb: To make things simpler, you can unselect the options `Search in comments and strings` and `Search for text occurrences` ![Usages detected](../images/remove/UnsafeDelete.png) diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md index 4fb62a83ef6..75b456a10de 100644 --- a/docs/tutorials/TracingCode.md +++ b/docs/tutorials/TracingCode.md @@ -39,7 +39,7 @@ In our case, we would want to begin the tracing at the very point where the App -According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `seedu.address.logic.Logic`. +According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `manageezpz.logic.Logic`. @@ -48,7 +48,7 @@ According to the sequence diagram you saw earlier (and repeated above for refere :bulb: **Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
-A quick look at the `seedu.address.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for. +A quick look at the `manageezpz.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for. ```java public interface Logic { @@ -190,7 +190,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [ public CommandResult execute(Model model) throws CommandException { ... Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); + Person editedPerson = createEditedPerson(personToEdit, editEmployeeDescriptor); if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { throw new CommandException(MESSAGE_DUPLICATE_PERSON); } diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/manageezpz/AppParameters.java similarity index 93% rename from src/main/java/seedu/address/AppParameters.java rename to src/main/java/manageezpz/AppParameters.java index ab552c398f3..69004074249 100644 --- a/src/main/java/seedu/address/AppParameters.java +++ b/src/main/java/manageezpz/AppParameters.java @@ -1,4 +1,4 @@ -package seedu.address; +package manageezpz; import java.nio.file.Path; import java.nio.file.Paths; @@ -7,8 +7,8 @@ import java.util.logging.Logger; import javafx.application.Application; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.util.FileUtil; +import manageezpz.commons.core.LogsCenter; +import manageezpz.commons.util.FileUtil; /** * Represents the parsed command-line parameters given to the application. diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/manageezpz/Main.java similarity index 97% rename from src/main/java/seedu/address/Main.java rename to src/main/java/manageezpz/Main.java index 052a5068631..d827b8705fd 100644 --- a/src/main/java/seedu/address/Main.java +++ b/src/main/java/manageezpz/Main.java @@ -1,4 +1,4 @@ -package seedu.address; +package manageezpz; import javafx.application.Application; diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/manageezpz/MainApp.java similarity index 79% rename from src/main/java/seedu/address/MainApp.java rename to src/main/java/manageezpz/MainApp.java index 4133aaa0151..4f92621f7bd 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/manageezpz/MainApp.java @@ -1,4 +1,4 @@ -package seedu.address; +package manageezpz; import java.io.IOException; import java.nio.file.Path; @@ -7,36 +7,36 @@ import javafx.application.Application; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.Version; -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.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; -import seedu.address.model.util.SampleDataUtil; -import seedu.address.storage.AddressBookStorage; -import seedu.address.storage.JsonAddressBookStorage; -import seedu.address.storage.JsonUserPrefsStorage; -import seedu.address.storage.Storage; -import seedu.address.storage.StorageManager; -import seedu.address.storage.UserPrefsStorage; -import seedu.address.ui.Ui; -import seedu.address.ui.UiManager; +import manageezpz.commons.core.Config; +import manageezpz.commons.core.LogsCenter; +import manageezpz.commons.core.Version; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.commons.util.ConfigUtil; +import manageezpz.commons.util.StringUtil; +import manageezpz.logic.Logic; +import manageezpz.logic.LogicManager; +import manageezpz.model.AddressBook; +import manageezpz.model.Model; +import manageezpz.model.ModelManager; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.ReadOnlyUserPrefs; +import manageezpz.model.UserPrefs; +import manageezpz.model.util.SampleDataUtil; +import manageezpz.storage.AddressBookStorage; +import manageezpz.storage.JsonAddressBookStorage; +import manageezpz.storage.JsonUserPrefsStorage; +import manageezpz.storage.Storage; +import manageezpz.storage.StorageManager; +import manageezpz.storage.UserPrefsStorage; +import manageezpz.ui.Ui; +import manageezpz.ui.UiManager; /** * Runs the application. */ public class MainApp extends Application { - public static final Version VERSION = new Version(0, 2, 0, true); + public static final Version VERSION = new Version(1, 4, 0, false); private static final Logger logger = LogsCenter.getLogger(MainApp.class); @@ -73,23 +73,25 @@ public void init() throws Exception { * The data from the sample address book will be used instead if {@code storage}'s address book is not found, * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book. */ - private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { + private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) throws IOException { Optional addressBookOptional; ReadOnlyAddressBook initialData; try { addressBookOptional = storage.readAddressBook(); if (!addressBookOptional.isPresent()) { - logger.info("Data file not found. Will be starting with a sample AddressBook"); + logger.info("Data file not found. Will be starting with sample data in ManageEZPZ"); } initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook); + storage.saveAddressBook(initialData); } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); + logger.warning("Data file not in the correct format. Will be starting with an empty ManageEZPZ"); initialData = new AddressBook(); - } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); + storage.saveAddressBook(initialData); + } catch (IOException | IllegalArgumentException e) { + logger.warning("Problem while reading from the file. Will be starting with an empty ManageEZPZ"); initialData = new AddressBook(); + storage.saveAddressBook(initialData); } - return new ModelManager(initialData, userPrefs); } @@ -151,7 +153,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { + "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 ManageEZPZ"); initializedPrefs = new UserPrefs(); } @@ -167,7 +169,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { @Override public void start(Stage primaryStage) { - logger.info("Starting AddressBook " + MainApp.VERSION); + logger.info("Starting ManageEZPZ " + MainApp.VERSION); ui.start(primaryStage); } diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/manageezpz/commons/core/Config.java similarity index 97% rename from src/main/java/seedu/address/commons/core/Config.java rename to src/main/java/manageezpz/commons/core/Config.java index 91145745521..204bcf94eab 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/manageezpz/commons/core/Config.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package manageezpz.commons.core; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/manageezpz/commons/core/GuiSettings.java similarity index 92% rename from src/main/java/seedu/address/commons/core/GuiSettings.java rename to src/main/java/manageezpz/commons/core/GuiSettings.java index ba33653be67..6c4e6f6b973 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/manageezpz/commons/core/GuiSettings.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package manageezpz.commons.core; import java.awt.Point; import java.io.Serializable; @@ -11,7 +11,7 @@ public class GuiSettings implements Serializable { private static final double DEFAULT_HEIGHT = 600; - private static final double DEFAULT_WIDTH = 740; + private static final double DEFAULT_WIDTH = 850; private final double windowWidth; private final double windowHeight; @@ -52,7 +52,7 @@ public boolean equals(Object other) { if (other == this) { return true; } - if (!(other instanceof GuiSettings)) { //this handles null as well. + if (!(other instanceof GuiSettings)) { // this handles null as well return false; } diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/manageezpz/commons/core/LogsCenter.java similarity index 97% rename from src/main/java/seedu/address/commons/core/LogsCenter.java rename to src/main/java/manageezpz/commons/core/LogsCenter.java index 431e7185e76..871ec6151e3 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/manageezpz/commons/core/LogsCenter.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package manageezpz.commons.core; import java.io.IOException; import java.util.Arrays; @@ -18,7 +18,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 = "ManageEZPZ.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/manageezpz/commons/core/Messages.java b/src/main/java/manageezpz/commons/core/Messages.java new file mode 100644 index 00000000000..35725365508 --- /dev/null +++ b/src/main/java/manageezpz/commons/core/Messages.java @@ -0,0 +1,33 @@ +package manageezpz.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!"; + public static final String MESSAGE_INVALID_COMMAND_FORMAT_BIND = "Invalid command format! \n\n%1$s"; + + public static final String MESSAGE_EMPTY_NAME = "Name field cannot be empty! \n\n%1$s"; + + public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = + "The person index provided is invalid as it exceeds the amount of persons in the displayed list! \n\n%1$s"; + public static final String MESSAGE_INVALID_TASK_DISPLAYED_INDEX = + "The task index provided is invalid as it exceeds the amount of tasks in the displayed list! \n\n%1$s"; + + public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; + public static final String MESSAGE_TASKS_LISTED_OVERVIEW = "%1$d tasks listed!"; + + public static final String MESSAGE_INVALID_TASK_TYPE = "Task is an invalid Task Type!"; + public static final String MESSAGE_INVALID_TIME_RANGE = + "The time range you provided is invalid as end time should be after start time!"; + public static final String MESSAGE_INVALID_TIME_FORMAT = "Invalid time format!"; + + public static final String MESSAGE_DUPLICATE_PERSON = "Employee, phone number or email " + + "already exists in manageEZPZ! Please check again! \n\n%1$s"; + + public static final String MESSAGE_DUPLICATE_TASK = "Task with the same description '%1$s' already exists! \n\n"; + + public static final String MESSAGE_FIELD_NOT_EDITED = "At least one of the fields to edit must be provided. \n\n"; +} diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/manageezpz/commons/core/Version.java similarity index 98% rename from src/main/java/seedu/address/commons/core/Version.java rename to src/main/java/manageezpz/commons/core/Version.java index 12142ec1e32..dfb8e373a8a 100644 --- a/src/main/java/seedu/address/commons/core/Version.java +++ b/src/main/java/manageezpz/commons/core/Version.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package manageezpz.commons.core; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/manageezpz/commons/core/index/Index.java similarity index 97% rename from src/main/java/seedu/address/commons/core/index/Index.java rename to src/main/java/manageezpz/commons/core/index/Index.java index 19536439c09..1a5c93cc83a 100644 --- a/src/main/java/seedu/address/commons/core/index/Index.java +++ b/src/main/java/manageezpz/commons/core/index/Index.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core.index; +package manageezpz.commons.core.index; /** * Represents a zero-based or one-based index. diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/manageezpz/commons/exceptions/DataConversionException.java similarity index 84% rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java rename to src/main/java/manageezpz/commons/exceptions/DataConversionException.java index 1f689bd8e3f..28908f5f35e 100644 --- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java +++ b/src/main/java/manageezpz/commons/exceptions/DataConversionException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package manageezpz.commons.exceptions; /** * Represents an error during conversion of data from one format to another diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/manageezpz/commons/exceptions/IllegalValueException.java similarity index 93% rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java rename to src/main/java/manageezpz/commons/exceptions/IllegalValueException.java index 19124db485c..609d6e2cdfd 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/manageezpz/commons/exceptions/IllegalValueException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package manageezpz.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/manageezpz/commons/util/AppUtil.java similarity index 94% rename from src/main/java/seedu/address/commons/util/AppUtil.java rename to src/main/java/manageezpz/commons/util/AppUtil.java index 87aa89c0326..2194f595aeb 100644 --- a/src/main/java/seedu/address/commons/util/AppUtil.java +++ b/src/main/java/manageezpz/commons/util/AppUtil.java @@ -1,9 +1,9 @@ -package seedu.address.commons.util; +package manageezpz.commons.util; import static java.util.Objects.requireNonNull; import javafx.scene.image.Image; -import seedu.address.MainApp; +import manageezpz.MainApp; /** * A container for App specific utility functions diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/manageezpz/commons/util/CollectionUtil.java similarity index 96% rename from src/main/java/seedu/address/commons/util/CollectionUtil.java rename to src/main/java/manageezpz/commons/util/CollectionUtil.java index eafe4dfd681..6b28b26ae75 100644 --- a/src/main/java/seedu/address/commons/util/CollectionUtil.java +++ b/src/main/java/manageezpz/commons/util/CollectionUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package manageezpz.commons.util; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/manageezpz/commons/util/ConfigUtil.java similarity index 77% rename from src/main/java/seedu/address/commons/util/ConfigUtil.java rename to src/main/java/manageezpz/commons/util/ConfigUtil.java index f7f8a2bd44c..e7945653f3a 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/manageezpz/commons/util/ConfigUtil.java @@ -1,11 +1,11 @@ -package seedu.address.commons.util; +package manageezpz.commons.util; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.core.Config; -import seedu.address.commons.exceptions.DataConversionException; +import manageezpz.commons.core.Config; +import manageezpz.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/manageezpz/commons/util/FileUtil.java similarity index 96% rename from src/main/java/seedu/address/commons/util/FileUtil.java rename to src/main/java/manageezpz/commons/util/FileUtil.java index b1e2767cdd9..f4748798efa 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/manageezpz/commons/util/FileUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package manageezpz.commons.util; import java.io.IOException; import java.nio.file.Files; @@ -18,7 +18,7 @@ public static boolean isFileExists(Path file) { } /** - * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)}, + * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String, String...)}, * otherwise returns false. * @param path A string representing the file path. Cannot be null. */ diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/manageezpz/commons/util/JsonUtil.java similarity index 97% rename from src/main/java/seedu/address/commons/util/JsonUtil.java rename to src/main/java/manageezpz/commons/util/JsonUtil.java index 8ef609f055d..950b8427e06 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/manageezpz/commons/util/JsonUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package manageezpz.commons.util; import static java.util.Objects.requireNonNull; @@ -20,8 +20,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 manageezpz.commons.core.LogsCenter; +import manageezpz.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/manageezpz/commons/util/StringUtil.java similarity index 95% rename from src/main/java/seedu/address/commons/util/StringUtil.java rename to src/main/java/manageezpz/commons/util/StringUtil.java index 61cc8c9a1cb..a8436fff718 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/manageezpz/commons/util/StringUtil.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package manageezpz.commons.util; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static manageezpz.commons.util.AppUtil.checkArgument; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/manageezpz/logic/Logic.java similarity index 67% rename from src/main/java/seedu/address/logic/Logic.java rename to src/main/java/manageezpz/logic/Logic.java index 92cd8fa605a..f5319dab994 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/manageezpz/logic/Logic.java @@ -1,14 +1,15 @@ -package seedu.address.logic; +package manageezpz.logic; import java.nio.file.Path; import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; +import manageezpz.commons.core.GuiSettings; +import manageezpz.logic.commands.CommandResult; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; /** * API of the Logic component @@ -26,13 +27,16 @@ public interface Logic { /** * Returns the AddressBook. * - * @see seedu.address.model.Model#getAddressBook() + * @see manageezpz.model.Model#getAddressBook() */ ReadOnlyAddressBook getAddressBook(); /** Returns an unmodifiable view of the filtered list of persons */ ObservableList getFilteredPersonList(); + /** Returns an unmodifiable view of the filtered list of tasks */ + ObservableList getFilteredTaskList(); + /** * Returns the user prefs' address book file path. */ diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/manageezpz/logic/LogicManager.java similarity index 60% rename from src/main/java/seedu/address/logic/LogicManager.java rename to src/main/java/manageezpz/logic/LogicManager.java index 9d9c6d15bdc..9a80d5dce6c 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/manageezpz/logic/LogicManager.java @@ -1,27 +1,33 @@ -package seedu.address.logic; +package manageezpz.logic; import java.io.IOException; import java.nio.file.Path; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -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.AddressBookParser; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.Model; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; -import seedu.address.storage.Storage; +import manageezpz.commons.core.GuiSettings; +import manageezpz.commons.core.LogsCenter; +import manageezpz.logic.commands.Command; +import manageezpz.logic.commands.CommandResult; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.logic.parser.AddressBookParser; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.Model; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; +import manageezpz.storage.Storage; /** * The main LogicManager of the app. */ public class LogicManager implements Logic { public static final String FILE_OPS_ERROR_MESSAGE = "Could not save data to file: "; + + public static final String INPUT_CONTAINS_SPECIAL_CHARACTERS = "Please do not use invisible characters!"; + private final Logger logger = LogsCenter.getLogger(LogicManager.class); private final Model model; @@ -41,6 +47,18 @@ public LogicManager(Model model, Storage storage) { public CommandResult execute(String commandText) throws CommandException, ParseException { logger.info("----------------[USER COMMAND][" + commandText + "]"); + //@@author ChanWeiJie-reused + //Reused from https://stackoverflow.com/a/1795436 + //with minor modifications + Pattern pattern = Pattern.compile("[\\p{C}]"); + Matcher matcher = pattern.matcher(commandText); + boolean isInvalid = matcher.find(); + //@@author + + if (isInvalid) { + throw new ParseException(INPUT_CONTAINS_SPECIAL_CHARACTERS); + } + CommandResult commandResult; Command command = addressBookParser.parseCommand(commandText); commandResult = command.execute(model); @@ -64,6 +82,11 @@ public ObservableList getFilteredPersonList() { return model.getFilteredPersonList(); } + @Override + public ObservableList getFilteredTaskList() { + return model.getFilteredTaskList(); + } + @Override public Path getAddressBookFilePath() { return model.getAddressBookFilePath(); diff --git a/src/main/java/manageezpz/logic/commands/AddDeadlineTaskCommand.java b/src/main/java/manageezpz/logic/commands/AddDeadlineTaskCommand.java new file mode 100644 index 00000000000..f15d12a8939 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/AddDeadlineTaskCommand.java @@ -0,0 +1,52 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_DUPLICATE_TASK; +import static manageezpz.logic.parser.CliSyntax.PREFIX_BY_DATETIME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.task.Deadline; + +public class AddDeadlineTaskCommand extends Command { + + public static final String COMMAND_WORD = "addDeadline"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Adds a Deadline Task to ManageEZPZ.\n" + + "Parameters: " + + PREFIX_DESCRIPTION + "DESCRIPTION " + + PREFIX_BY_DATETIME + "DATE TIME\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_DESCRIPTION + "Do Daily Commissions " + + PREFIX_BY_DATETIME + "2022-03-15 0400"; + + public static final String MESSAGE_SUCCESS = "New Deadline Task added: %1$s"; + + private final Deadline toAdd; + + public AddDeadlineTaskCommand(Deadline deadline) { + toAdd = deadline; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasTask(toAdd)) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_TASK, + toAdd.getDescription()) + MESSAGE_USAGE); + } + + model.addDeadline(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddDeadlineTaskCommand // instanceof handles nulls + && toAdd.equals(((AddDeadlineTaskCommand) other).toAdd)); + } +} diff --git a/src/main/java/manageezpz/logic/commands/AddEmployeeCommand.java b/src/main/java/manageezpz/logic/commands/AddEmployeeCommand.java new file mode 100644 index 00000000000..e866c8342c5 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/AddEmployeeCommand.java @@ -0,0 +1,64 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EMAIL; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PHONE; + +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Person; + +/** + * Adds a person to the address book. + */ +public class AddEmployeeCommand extends Command { + + public static final String COMMAND_WORD = "addEmployee"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Adds an Employee to ManageEZPZ.\n" + + "Parameters: " + + PREFIX_NAME + "NAME " + + PREFIX_PHONE + "PHONE " + + PREFIX_EMAIL + "EMAIL\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_NAME + "John Doe " + + PREFIX_PHONE + "98765432 " + + PREFIX_EMAIL + "johnd@example.com"; + + public static final String MESSAGE_SUCCESS = "New Employee added: %1$s"; + + public static final String MESSAGE_DUPLICATE_PERSON = "Employee, phone number or " + + "email already exists in manageEZPZ! " + + "Please check again!\n"; + + private final Person toAdd; + + /** + * Creates an AddEmployeeCommand to add the specified {@code Person} + */ + public AddEmployeeCommand(Person person) { + requireNonNull(person); + toAdd = person; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasPerson(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_PERSON + "\n" + MESSAGE_USAGE); + } + + model.addPerson(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddEmployeeCommand // instanceof handles nulls + && toAdd.equals(((AddEmployeeCommand) other).toAdd)); + } +} diff --git a/src/main/java/manageezpz/logic/commands/AddEventTaskCommand.java b/src/main/java/manageezpz/logic/commands/AddEventTaskCommand.java new file mode 100644 index 00000000000..fb7bfc2a4c2 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/AddEventTaskCommand.java @@ -0,0 +1,52 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_DUPLICATE_TASK; +import static manageezpz.logic.parser.CliSyntax.PREFIX_AT_DATETIME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.task.Event; + +public class AddEventTaskCommand extends Command { + + public static final String COMMAND_WORD = "addEvent"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Adds an Event Task to ManageEZPZ.\n" + + "Parameters: " + + PREFIX_DESCRIPTION + "DESCRIPTION " + + PREFIX_AT_DATETIME + "DATE START_TIME END_TIME\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_DESCRIPTION + "Finish 160 Resins " + + PREFIX_AT_DATETIME + "2022-03-15 1800 2000"; + + public static final String MESSAGE_SUCCESS = "New Event Task added: %1$s"; + + private final Event toAdd; + + public AddEventTaskCommand(Event event) { + toAdd = event; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasTask(toAdd)) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_TASK, + toAdd.getDescription()) + MESSAGE_USAGE); + } + + model.addEvent(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddEventTaskCommand // instanceof handles nulls + && toAdd.equals(((AddEventTaskCommand) other).toAdd)); + } +} diff --git a/src/main/java/manageezpz/logic/commands/AddTodoTaskCommand.java b/src/main/java/manageezpz/logic/commands/AddTodoTaskCommand.java new file mode 100644 index 00000000000..18e91a49a87 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/AddTodoTaskCommand.java @@ -0,0 +1,54 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_DUPLICATE_TASK; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.task.Todo; + +public class AddTodoTaskCommand extends Command { + + public static final String COMMAND_WORD = "addTodo"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Adds a Todo Task to ManageEZPZ.\n" + + "Parameters: " + + PREFIX_DESCRIPTION + "DESCRIPTION\n" + + "Example: " + COMMAND_WORD + " " + + PREFIX_DESCRIPTION + "Play Genshin Impact"; + + public static final String MESSAGE_SUCCESS = "New Todo Task added: %1$s"; + + private final Todo toAdd; + + /** + * Creates an AddTodoTaskCommand to add the specified {@code Task} + * @param task Task to be added. + */ + public AddTodoTaskCommand(Todo task) { + requireNonNull(task); + toAdd = task; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasTask(toAdd)) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_TASK, + toAdd.getDescription()) + MESSAGE_USAGE); + } + + model.addTodo(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddTodoTaskCommand // instanceof handles nulls + && toAdd.equals(((AddTodoTaskCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/manageezpz/logic/commands/ClearCommand.java similarity index 66% rename from src/main/java/seedu/address/logic/commands/ClearCommand.java rename to src/main/java/manageezpz/logic/commands/ClearCommand.java index 9c86b1fa6e4..26083c96cf2 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/manageezpz/logic/commands/ClearCommand.java @@ -1,9 +1,9 @@ -package seedu.address.logic.commands; +package manageezpz.logic.commands; import static java.util.Objects.requireNonNull; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; +import manageezpz.model.AddressBook; +import manageezpz.model.Model; /** * Clears the address book. @@ -11,7 +11,7 @@ public class ClearCommand extends Command { public static final String COMMAND_WORD = "clear"; - public static final String MESSAGE_SUCCESS = "Address book has been cleared!"; + public static final String MESSAGE_SUCCESS = "ManageEZPZ has been cleared!"; @Override diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/manageezpz/logic/commands/Command.java similarity index 78% rename from src/main/java/seedu/address/logic/commands/Command.java rename to src/main/java/manageezpz/logic/commands/Command.java index 64f18992160..a75bf697adc 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/manageezpz/logic/commands/Command.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands; +package manageezpz.logic.commands; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; /** * Represents a command with hidden internal logic and the ability to be executed. diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/manageezpz/logic/commands/CommandResult.java similarity index 97% rename from src/main/java/seedu/address/logic/commands/CommandResult.java rename to src/main/java/manageezpz/logic/commands/CommandResult.java index 92f900b7916..181998eb4eb 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/manageezpz/logic/commands/CommandResult.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package manageezpz.logic.commands; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/manageezpz/logic/commands/DeleteEmployeeCommand.java b/src/main/java/manageezpz/logic/commands/DeleteEmployeeCommand.java new file mode 100644 index 00000000000..2e9c4e037a0 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/DeleteEmployeeCommand.java @@ -0,0 +1,75 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX; + +import java.util.List; +import java.util.stream.Collectors; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; + +/** + * Deletes an employee identified using its displayed index from the address book. + */ +public class DeleteEmployeeCommand extends Command { + + public static final String COMMAND_WORD = "deleteEmployee"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the employee identified by the index number used in the displayed employee list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Employee: %1$s"; + + private final Index targetIndex; + + /** + * Constructor to initialize an instance of DeleteEmployeeCommand class + * with the given targetIndex. + * + * @param targetIndex Index of the Employee to be deleted + */ + public DeleteEmployeeCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownPersonList = model.getFilteredPersonList(); + List fullTaskList = model.getAddressBook().getTaskList(); + + if (targetIndex.getZeroBased() >= lastShownPersonList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Person personToDelete = lastShownPersonList.get(targetIndex.getZeroBased()); + + List affectedTaskList = fullTaskList.stream() + .filter(task -> task.getAssignees().contains(personToDelete)) + .collect(Collectors.toList()); + + for (Task task : affectedTaskList) { + model.untagEmployeeFromTask(task, personToDelete); + } + + model.deletePerson(personToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DeleteEmployeeCommand // instanceof handles nulls + && targetIndex.equals(((DeleteEmployeeCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/manageezpz/logic/commands/DeleteTaskCommand.java b/src/main/java/manageezpz/logic/commands/DeleteTaskCommand.java new file mode 100644 index 00000000000..876b711a82c --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/DeleteTaskCommand.java @@ -0,0 +1,73 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; + +/** + * Deletes a task identified using its displayed index from the address book. + */ +public class DeleteTaskCommand extends Command { + + public static final String COMMAND_WORD = "deleteTask"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the task identified by the index number used in the displayed task list.\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"; + + private final Index targetIndex; + + /** + * Constructor to initialize an instance of DeleteTaskCommand class + * with the given targetIndex. + * + * @param targetIndex Index of the Task to be deleted + */ + public DeleteTaskCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownTaskList = model.getFilteredTaskList(); + List fullPersonList = model.getAddressBook().getPersonList(); + + if (targetIndex.getZeroBased() >= lastShownTaskList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task taskToDelete = lastShownTaskList.get(targetIndex.getZeroBased()); + + List affectedPersonList = taskToDelete.getAssignees(); + + for (Person person : affectedPersonList) { + Person personToUpdate = fullPersonList.get(fullPersonList.indexOf(person)); + model.decreaseNumOfTasks(personToUpdate); + } + + model.deleteTask(taskToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DeleteTaskCommand // instanceof handles nulls + && targetIndex.equals(((DeleteTaskCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/manageezpz/logic/commands/EditEmployeeCommand.java b/src/main/java/manageezpz/logic/commands/EditEmployeeCommand.java new file mode 100644 index 00000000000..89f7083833a --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/EditEmployeeCommand.java @@ -0,0 +1,213 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_DUPLICATE_PERSON; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EMAIL; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PHONE; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import manageezpz.commons.core.index.Index; +import manageezpz.commons.util.CollectionUtil; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.Person; +import manageezpz.model.person.Phone; +import manageezpz.model.task.Task; + +/** + * Edits the details of an existing employee in the address book. + */ +public class EditEmployeeCommand extends Command { + + public static final String COMMAND_WORD = "editEmployee"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Edits the details of the employee identified by the " + + "index number used in the displayed employee list.\n" + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + PREFIX_NAME + "NAME " + + PREFIX_PHONE + "PHONE " + + PREFIX_EMAIL + "EMAIL\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_PHONE + "91234567 " + + PREFIX_EMAIL + "johndoe@example.com"; + + public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Update Employee success: %1$s"; + + private final Index index; + private final EditEmployeeDescriptor editEmployeeDescriptor; + + /** + * Constructor to initialize a EditEmployeeCommand class with the given + * index and editEmployeeDescriptor. + * + * @param index Index of the Employee to edit + * @param editEmployeeDescriptor Details of the Employee to edit + */ + public EditEmployeeCommand(Index index, EditEmployeeDescriptor editEmployeeDescriptor) { + requireNonNull(index); + requireNonNull(editEmployeeDescriptor); + + this.index = index; + this.editEmployeeDescriptor = new EditEmployeeDescriptor(editEmployeeDescriptor); + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownPersonList = model.getFilteredPersonList(); + List fullPersonList = model.getAddressBook().getPersonList(); + List fullTaskList = model.getAddressBook().getTaskList(); + + if (index.getZeroBased() >= lastShownPersonList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Person personToEdit = lastShownPersonList.get(index.getZeroBased()); + Person editedPerson = createEditedEmployee(personToEdit, editEmployeeDescriptor); + + // Check for same person (i.e., name, phone or email already exists) + for (Person person : fullPersonList) { + if (!person.equals(personToEdit) && person.isSamePerson(editedPerson)) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_PERSON, MESSAGE_USAGE)); + } + } + + model.setPerson(personToEdit, editedPerson); + + List affectedTaskList = fullTaskList.stream() + .filter(task -> task.getAssignees().contains(personToEdit)) + .collect(Collectors.toList()); + + for (Task task : affectedTaskList) { + List assignees = task.getAssignees(); + + for (Person assignee : assignees) { + if (assignee.equals(personToEdit)) { + Task taskToUpdate = fullTaskList.get(fullTaskList.indexOf(task)); + model.updateTaskWithEditedPerson(taskToUpdate, assignees.indexOf(assignee), editedPerson); + } + } + } + + return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); + } + + /** + * Creates and returns a {@code Person} with the details of {@code personToEdit} + * edited with {@code editEmployeeDescriptor}. + */ + public static Person createEditedEmployee(Person personToEdit, EditEmployeeDescriptor editEmployeeDescriptor) { + assert personToEdit != null; + + Name updatedName = editEmployeeDescriptor.getName().orElse(personToEdit.getName()); + Phone updatedPhone = editEmployeeDescriptor.getPhone().orElse(personToEdit.getPhone()); + Email updatedEmail = editEmployeeDescriptor.getEmail().orElse(personToEdit.getEmail()); + int personToEditNumOfTask = personToEdit.getNumOfTasks(); + + return new Person(updatedName, updatedPhone, updatedEmail, personToEditNumOfTask); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditEmployeeCommand)) { + return false; + } + + // state check + EditEmployeeCommand e = (EditEmployeeCommand) other; + return index.equals(e.index) + && editEmployeeDescriptor.equals(e.editEmployeeDescriptor); + } + + /** + * 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 EditEmployeeDescriptor { + private Name name; + private Phone phone; + private Email email; + + public EditEmployeeDescriptor() {} + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditEmployeeDescriptor(EditEmployeeDescriptor toCopy) { + setName(toCopy.name); + setPhone(toCopy.phone); + setEmail(toCopy.email); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(name, phone, email); + } + + public void setName(Name name) { + this.name = name; + } + + public Optional getName() { + return Optional.ofNullable(name); + } + + public void setPhone(Phone phone) { + this.phone = phone; + } + + public Optional getPhone() { + return Optional.ofNullable(phone); + } + + public void setEmail(Email email) { + this.email = email; + } + + public Optional getEmail() { + return Optional.ofNullable(email); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditEmployeeDescriptor)) { + return false; + } + + // state check + EditEmployeeDescriptor e = (EditEmployeeDescriptor) other; + + return getName().equals(e.getName()) + && getPhone().equals(e.getPhone()) + && getEmail().equals(e.getEmail()); + } + } +} diff --git a/src/main/java/manageezpz/logic/commands/EditTaskCommand.java b/src/main/java/manageezpz/logic/commands/EditTaskCommand.java new file mode 100644 index 00000000000..21dfe7fc79b --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/EditTaskCommand.java @@ -0,0 +1,275 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_DUPLICATE_TASK; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_TYPE; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TIME_RANGE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_AT_DATETIME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DATE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import java.util.HashMap; +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.logic.parser.ParserUtil; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.Model; +import manageezpz.model.task.Date; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Description; +import manageezpz.model.task.Event; +import manageezpz.model.task.Task; +import manageezpz.model.task.Time; +import manageezpz.model.task.Todo; +import manageezpz.model.task.exceptions.DuplicateTaskException; + +/** + * Edits the details of an existing task in the address book. + */ +public class EditTaskCommand extends Command { + + public static final String COMMAND_WORD = "editTask"; + + public static final String EXAMPLE_ONE = COMMAND_WORD + " 1 " + PREFIX_DESCRIPTION + "Eat bananas"; + + public static final String EXAMPLE_TWO = COMMAND_WORD + " 2 " + PREFIX_DESCRIPTION + "Eat Apple " + + PREFIX_DATE + "2022-09-05 " + PREFIX_AT_DATETIME + "1800"; + + public static final String EXAMPLE_THREE = COMMAND_WORD + " 3 " + PREFIX_DESCRIPTION + "Midterm Exam " + + PREFIX_DATE + "2022-04-06 " + PREFIX_AT_DATETIME + "1800 2000"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Edits the details of the Task identified " + + "by the index number used in the displayed task list.\n" + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must exist in the Address Book) " + + PREFIX_DESCRIPTION + "DESCRIPTION " + + PREFIX_DATE + "DATE " + + PREFIX_AT_DATETIME + "TIME\n" + + "At least one of " + PREFIX_DESCRIPTION + " " + PREFIX_DATE + + " " + PREFIX_AT_DATETIME + " must have a value.\n" + + "For an Event Task, a start time and an end time " + + "separated with an empty space must be provided " + + "instead of a single time value.\n" + + "Example 1: " + EXAMPLE_ONE + "\n" + + "Example 2: " + EXAMPLE_TWO + "\n" + + "Example 3: " + EXAMPLE_THREE; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Update Task success: %1$s"; + + public static final String MESSAGE_EDIT_TASK_NO_EMPTY_VALUES = + "For Deadline Task or Event Task, either desc/ date/ or at/ must have a value after it!"; + + public static final String MESSAGE_EDIT_TODO_TASK_NO_DATE_AND_TIME_VALUES = + "A Todo Task does not have a date or time to be edited!"; + + public static final String MESSAGE_INVALID_TIME_DETAILS_EVENT_TASK = + "Invalid time details for Event Task! Event Task should have start time and end time!"; + + private final Index index; + private final String desc; + private final String date; + private final String time; + private final HashMap prefixStatusHash; + + /** + * Constructor to initialize an instance of EditTaskCommand class + * with the given index and updated description, date and time + * information. + * + * @param index Index of the Task to edit information + * @param desc New description of the Task + * @param date New date of the Task + * @param time New time of the Task + * @param prefixStatusHash Indicate whether user had declared a prefix + */ + public EditTaskCommand(Index index, String desc, String date, String time, + HashMap prefixStatusHash) { + this.index = index; + this.desc = desc; + this.date = date; + this.time = time; + this.prefixStatusHash = prefixStatusHash; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownList = model.getFilteredTaskList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task currentTask = lastShownList.get(index.getZeroBased()); + Task updatedTask; + + try { + if (currentTask.getType().equalsIgnoreCase("todo")) { + updatedTask = updateTodo((Todo) currentTask, this.desc); + } else if (currentTask.getType().equalsIgnoreCase("deadline")) { + updatedTask = updateDeadline((Deadline) currentTask, this.desc, this.date, this.time); + } else if (currentTask.getType().equalsIgnoreCase("event")) { + updatedTask = updateEvent((Event) currentTask, this.desc, this.date, this.time); + } else { + // Should not reach this as there are only three types of tasks + throw new CommandException(MESSAGE_INVALID_TASK_TYPE); + } + + model.setTask(currentTask, updatedTask); + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, updatedTask)); + } catch (ParseException pe) { + throw new CommandException(pe.getMessage() + "\n\n" + EditTaskCommand.MESSAGE_USAGE, pe); + } catch (DuplicateTaskException de) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_TASK, this.desc) + MESSAGE_USAGE, de); + } + } + + /** + * If the value after a prefix is empty, return false. + * Else, return true. + */ + private boolean ensureFormatCompliance(HashMap prefixStatusHash, + String desc, String date, String time) { + boolean isFormatOkay = true; + + HashMap inputStatusHash = new HashMap<>(); + inputStatusHash.put("description", desc); + inputStatusHash.put("date", date); + inputStatusHash.put("datetime", time); + + String[] statusArr = {"description", "date", "datetime"}; + + for (String s : statusArr) { + boolean status = prefixStatusHash.get(s); + String input = inputStatusHash.get(s).trim(); + if (status && input.isEmpty()) { + isFormatOkay = false; + break; + } + } + return isFormatOkay; + } + + /** + * Updates a Todo task. + * + * @param currentTask Current Todo task that is to be updated + * @param desc New description of the Todo Task + * @return Updated Todo task + */ + public Task updateTodo(Todo currentTask, String desc) throws ParseException { + Todo updatedToDoTask = new Todo(currentTask); + + if (prefixStatusHash.get("date") || prefixStatusHash.get("datetime")) { + throw new ParseException(MESSAGE_EDIT_TODO_TASK_NO_DATE_AND_TIME_VALUES); + } + + Description newDesc = ParserUtil.parseDescription(desc); + updatedToDoTask.setDescription(newDesc); + + return updatedToDoTask; + } + + /** + * Updates a Deadline task. + * + * @param currentTask Current Deadline task that is to be updated + * @param desc New description of the Deadline Task + * @param date New date of the Deadline Task + * @param time New time of the Deadline Task + * @return Updated Deadline task + */ + public Task updateDeadline(Deadline currentTask, String desc, String date, String time) throws ParseException { + Deadline updatedDeadlineTask = new Deadline(currentTask); + + if (!ensureFormatCompliance(prefixStatusHash, desc, date, time)) { + throw new ParseException(MESSAGE_EDIT_TASK_NO_EMPTY_VALUES); + } + + if (!desc.isEmpty()) { + Description newDesc = ParserUtil.parseDescription(desc); + updatedDeadlineTask.setDescription(newDesc); + } + + if (!date.isEmpty()) { + Date newDate = ParserUtil.parseDate(date); + updatedDeadlineTask.setDate(newDate); + } + + if (!time.isEmpty()) { + Time newTime = ParserUtil.parseTime(time); + updatedDeadlineTask.setTime(newTime); + } + + return updatedDeadlineTask; + } + + /** + * Updates an Event task. + * + * @param currentTask Current Event task that is to be updated + * @param desc New description of the Event Task + * @param date New date of the Event Task + * @param time New time of the Event Task + * @return Updated Event task + */ + public Task updateEvent(Event currentTask, String desc, String date, String time) throws ParseException { + Event updatedEventTask = new Event(currentTask); + + if (!ensureFormatCompliance(prefixStatusHash, desc, date, time)) { + throw new ParseException(MESSAGE_EDIT_TASK_NO_EMPTY_VALUES); + } + + if (!desc.isEmpty()) { + Description newDesc = ParserUtil.parseDescription(desc); + updatedEventTask.setDescription(newDesc); + } + + if (!date.isEmpty()) { + Date newDate = ParserUtil.parseDate(date); + updatedEventTask.setDate(newDate); + } + + if (!time.isEmpty()) { + String[] newStartEndTimeStrParts = time.split(" "); + + if (newStartEndTimeStrParts.length != 2) { + throw new ParseException(MESSAGE_INVALID_TIME_DETAILS_EVENT_TASK); + } + + Time newStartTime = ParserUtil.parseTime(newStartEndTimeStrParts[0]); + Time newEndTime = ParserUtil.parseTime(newStartEndTimeStrParts[1]); + + if (newEndTime.getParsedTime().compareTo(newStartTime.getParsedTime()) < 1) { + throw new ParseException(MESSAGE_INVALID_TIME_RANGE); + } + + updatedEventTask.setStartTime(newStartTime); + updatedEventTask.setEndTime(newEndTime); + } + + return updatedEventTask; + } + + private boolean arePrefixStatusHashesEqual(HashMap other) { + return prefixStatusHash.get("description").equals(other.get("description")) + && prefixStatusHash.get("date").equals(other.get("date")) + && prefixStatusHash.get("datetime").equals(other.get("datetime")); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof EditTaskCommand // instanceof handles nulls + && index.equals(((EditTaskCommand) other).index) + && desc.equals(((EditTaskCommand) other).desc) + && date.equals(((EditTaskCommand) other).date) + && time.equals(((EditTaskCommand) other).time)) + && arePrefixStatusHashesEqual(((EditTaskCommand) other).prefixStatusHash); + } +} diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/manageezpz/logic/commands/ExitCommand.java similarity index 84% rename from src/main/java/seedu/address/logic/commands/ExitCommand.java rename to src/main/java/manageezpz/logic/commands/ExitCommand.java index 3dd85a8ba90..b6fd59bc6af 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/manageezpz/logic/commands/ExitCommand.java @@ -1,6 +1,6 @@ -package seedu.address.logic.commands; +package manageezpz.logic.commands; -import seedu.address.model.Model; +import manageezpz.model.Model; /** * Terminates the program. diff --git a/src/main/java/manageezpz/logic/commands/FindEmployeeCommand.java b/src/main/java/manageezpz/logic/commands/FindEmployeeCommand.java new file mode 100644 index 00000000000..354defe611a --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/FindEmployeeCommand.java @@ -0,0 +1,85 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EMAIL; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PHONE; + +import java.util.function.Predicate; + +import manageezpz.commons.core.Messages; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.PersonMultiplePredicate; +import manageezpz.model.person.Phone; + +/** + * The command to find employees based on the multiple properties given. + */ +public class FindEmployeeCommand extends Command { + + public static final String COMMAND_WORD = "findEmployee"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Finds all employees that contains the properties specified.\n" + + "Employee's properties:\n" + + PREFIX_NAME.getPrefix() + + "NAMES: Finds all employees which has their name contain any of the words in NAMES\n" + + PREFIX_PHONE.getPrefix() + + "PHONE NUMBER: Find employees with the exact phone number\n" + + PREFIX_EMAIL.getPrefix() + + "EMAIL: Finds employees with the exact email" + + "Example:\n" + + COMMAND_WORD + " " + PREFIX_NAME.getPrefix() + "Alex Yeoh\n" + + COMMAND_WORD + " " + PREFIX_PHONE.getPrefix() + "62226222\n" + + COMMAND_WORD + " " + PREFIX_EMAIL.getPrefix() + "alexyeo@google.com\n" + + COMMAND_WORD + " " + PREFIX_NAME.getPrefix() + "Benson Chua " + PREFIX_PHONE.getPrefix() + "6123456 " + + PREFIX_EMAIL.getPrefix() + "bensonc@gmail.com"; + + public static final String NO_OPTIONS = COMMAND_WORD + " needs at least 1 valid options\n"; + + public static final String INVALID_NAME = Name.MESSAGE_CONSTRAINTS + "\n"; + + public static final String INVALID_PHONE = Phone.MESSAGE_CONSTRAINTS + "\n"; + + public static final String INVALID_EMAIL = Email.MESSAGE_CONSTRAINTS + "\n"; + + private final PersonMultiplePredicate predicate; + + /** + * Constructor for the find employee command. + * @param predicate The predicate with multiple search terms to search for employees + */ + public FindEmployeeCommand(PersonMultiplePredicate predicate) { + this.predicate = predicate; + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + model.updateFilteredPersonList(predicate); + int latestNumberOfEmployees = model.getFilteredPersonList().size(); + String commandMessage = String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, latestNumberOfEmployees); + return new CommandResult(commandMessage); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof FindEmployeeCommand) { + Predicate otherPredicate = ((FindEmployeeCommand) obj).predicate; + boolean isOtherPredicateEqual = predicate.equals(otherPredicate); + return isOtherPredicateEqual; + } + return false; + } +} diff --git a/src/main/java/manageezpz/logic/commands/FindTaskCommand.java b/src/main/java/manageezpz/logic/commands/FindTaskCommand.java new file mode 100644 index 00000000000..1eb4ce6c3df --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/FindTaskCommand.java @@ -0,0 +1,116 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.logic.parser.CliSyntax.PREFIX_ASSIGNEES; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DATE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DEADLINE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EVENT; +import static manageezpz.logic.parser.CliSyntax.PREFIX_IS_MARKED; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PRIORITY; +import static manageezpz.logic.parser.CliSyntax.PREFIX_TODO; + +import java.util.function.Predicate; + +import manageezpz.commons.core.Messages; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Name; +import manageezpz.model.task.Date; +import manageezpz.model.task.Description; +import manageezpz.model.task.TaskMultiplePredicate; + + +/** + * A subclass for find command to find all the tasks. + */ +public class FindTaskCommand extends Command { + + public static final String COMMAND_WORD = "findTask"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Finds all tasks that contains the properties specified.\n" + + "Task Types:\n" + + PREFIX_TODO.getPrefix() + ": Todos\n" + + PREFIX_DEADLINE.getPrefix() + ": Deadlines\n" + + PREFIX_EVENT.getPrefix() + ": Events\n" + + "Options:\n" + + PREFIX_DESCRIPTION.getPrefix() + ": Description of the tasks\n" + + PREFIX_DATE.getPrefix() + ": Date of the task in YYYY-MM-DD (Only for deadline and event)\n" + + PREFIX_PRIORITY.getPrefix() + ": Priority of task. Only HIGH, MEDIUM, LOW and NONE\n" + + PREFIX_ASSIGNEES.getPrefix() + + ": The assignees that was assigned to the task (Only one full name of assignee allowed)\n" + + PREFIX_IS_MARKED.getPrefix() + ": Whether the task is marked. Only true or false." + + "Format:\n" + + COMMAND_WORD + " " + PREFIX_TODO.getPrefix() + "\n" + + COMMAND_WORD + " " + PREFIX_DEADLINE.getPrefix() + "\n" + + COMMAND_WORD + " " + PREFIX_EVENT.getPrefix() + "\n" + + COMMAND_WORD + " " + PREFIX_DESCRIPTION.getPrefix() + "[LIST OF WORDS]\n" + + COMMAND_WORD + " " + PREFIX_DATE.getPrefix() + "YYYY-MM-DD\n" + + COMMAND_WORD + " " + PREFIX_PRIORITY.getPrefix() + "PRIORITY" + + COMMAND_WORD + " " + PREFIX_ASSIGNEES.getPrefix() + "Assignee's full name\n" + + COMMAND_WORD + " " + PREFIX_IS_MARKED.getPrefix() + "BOOLEAN\n" + + "Example:\n" + + COMMAND_WORD + " " + PREFIX_DESCRIPTION.getPrefix() + "homework\n" + + COMMAND_WORD + " " + PREFIX_DATE.getPrefix() + "2022-01-01\n" + + COMMAND_WORD + " " + PREFIX_PRIORITY.getPrefix() + "HIGH\n" + + COMMAND_WORD + " " + PREFIX_ASSIGNEES.getPrefix() + "Sam Leong\n" + + COMMAND_WORD + " " + PREFIX_IS_MARKED.getPrefix() + "true\n" + + COMMAND_WORD + " " + PREFIX_DESCRIPTION.getPrefix() + "Capstone project " + PREFIX_DATE.getPrefix() + + "2022-05-01 " + PREFIX_PRIORITY.getPrefix() + "HIGH " + PREFIX_ASSIGNEES.getPrefix() + "Max Leong" + + PREFIX_IS_MARKED.getPrefix() + "true"; + + public static final String NO_OPTIONS = COMMAND_WORD + " needs at least 1 valid option\n"; + + public static final String INVALID_DESCRIPTION = Description.MESSAGE_CONSTRAINTS + "\n"; + + public static final String INVALID_DATE = Date.MESSAGE_CONSTRAINTS + "\n"; + + public static final String INVALID_PRIORITY = "Property should be NONE, LOW, MEDIUM, HIGH\n"; + + public static final String TODO_AND_DATE_OPTION_TOGETHER = "Todo and Date option are together\n"; + + public static final String INVALID_BOOLEAN = "Boolean should be true or false\n"; + + public static final String INVALID_ASSIGNEE = Name.MESSAGE_CONSTRAINTS + "\n"; + + public static final String MORE_THAN_ONE_TASK_TYPE = "Only one task type is allowed\n"; + + private final TaskMultiplePredicate predicate; + + /** + * The constructor for find task command. + * @param predicate The predicate as search terms to find task + */ + public FindTaskCommand(TaskMultiplePredicate predicate) { + requireNonNull(predicate); + this.predicate = predicate; + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + model.updateFilteredTaskList(predicate); + int latestNumberOfTasks = model.getFilteredTaskList().size(); + String commandResultMessage = String.format(Messages.MESSAGE_TASKS_LISTED_OVERVIEW, latestNumberOfTasks); + return new CommandResult(commandResultMessage); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof FindTaskCommand) { + Predicate otherPredicate = ((FindTaskCommand) obj).predicate; + boolean isOtherPredicateEqual = predicate.equals(otherPredicate); + return isOtherPredicateEqual; + } + return false; + } +} diff --git a/src/main/java/manageezpz/logic/commands/HelpCommand.java b/src/main/java/manageezpz/logic/commands/HelpCommand.java new file mode 100644 index 00000000000..ec0e691bb53 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/HelpCommand.java @@ -0,0 +1,22 @@ +package manageezpz.logic.commands; + +import manageezpz.model.Model; + +/** + * Format full help instructions for every command for display. + */ +public class HelpCommand extends Command { + + public static final String COMMAND_WORD = "help"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Shows program usage instructions.\n" + + "Example: " + COMMAND_WORD; + + public static final String MESSAGE_SHOWING_HELP = "Opened help window."; + + @Override + public CommandResult execute(Model model) { + return new CommandResult(MESSAGE_SHOWING_HELP, true, false); + } +} diff --git a/src/main/java/manageezpz/logic/commands/ListEmployeeCommand.java b/src/main/java/manageezpz/logic/commands/ListEmployeeCommand.java new file mode 100644 index 00000000000..17ab2ef6954 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/ListEmployeeCommand.java @@ -0,0 +1,23 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; + +import manageezpz.model.Model; + +/** + * Lists all persons in the address book to the user. + */ +public class ListEmployeeCommand extends Command { + public static final String COMMAND_WORD = "listEmployee"; + public static final String MESSAGE_ALL_SUCCESS = "Listed all Employees"; + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredPersonList(model.PREDICATE_SHOW_ALL_PERSONS); + return new CommandResult(MESSAGE_ALL_SUCCESS); + } +} diff --git a/src/main/java/manageezpz/logic/commands/ListTaskCommand.java b/src/main/java/manageezpz/logic/commands/ListTaskCommand.java new file mode 100644 index 00000000000..7c1f18b4d26 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/ListTaskCommand.java @@ -0,0 +1,23 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; + +import manageezpz.model.Model; + +/** + * Lists all persons in the address book to the user. + */ +public class ListTaskCommand extends Command { + public static final String COMMAND_WORD = "listTask"; + public static final String MESSAGE_ALL_SUCCESS = "Listed all Tasks"; + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredTaskList(model.PREDICATE_SHOW_ALL_TASKS); + return new CommandResult(MESSAGE_ALL_SUCCESS); + } +} diff --git a/src/main/java/manageezpz/logic/commands/MarkTaskCommand.java b/src/main/java/manageezpz/logic/commands/MarkTaskCommand.java new file mode 100644 index 00000000000..b171da3a14f --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/MarkTaskCommand.java @@ -0,0 +1,65 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.task.Task; + +/** + * Marks a task identified using its displayed index from the address book as done. + */ +public class MarkTaskCommand extends Command { + + public static final String COMMAND_WORD = "markTask"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Marks the task identified by the index number used in the displayed task list as done.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_MARK_TASK_SUCCESS = "Task set as done: %1$s"; + + private final Index targetIndex; + + /** + * Constructor to initialize an instance of MarkTaskCommand class + * with the given targetIndex. + * + * @param targetIndex Index of the Task to be marked as done + */ + public MarkTaskCommand(Index targetIndex) { + requireNonNull(targetIndex); + this.targetIndex = targetIndex; + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownList = model.getFilteredTaskList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task taskToMark = lastShownList.get(targetIndex.getZeroBased()); + Task markedTask = model.markTask(taskToMark); + + return new CommandResult(String.format(MESSAGE_MARK_TASK_SUCCESS, markedTask)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof MarkTaskCommand // instanceof handles nulls + && targetIndex.equals(((MarkTaskCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/manageezpz/logic/commands/TagTaskCommand.java b/src/main/java/manageezpz/logic/commands/TagTaskCommand.java new file mode 100644 index 00000000000..7e353ff09a3 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/TagTaskCommand.java @@ -0,0 +1,95 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; + +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; + +public class TagTaskCommand extends Command { + + public static final String COMMAND_WORD = "tagTask"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Tags the specified employee to the task identified by the " + + "index number used in the displayed task list.\n" + + "Parameters: INDEX (must be a positive integer) " + + PREFIX_NAME + "EMPLOYEE_FULL_NAME\n" + + "Example: " + COMMAND_WORD + " 1 " + PREFIX_NAME + "Alex Yeoh"; + + public static final String MESSAGE_TAG_TASK_SUCCESS = "Employee %1$s is tagged to the task: "; + + public static final String MESSAGE_NO_SUCH_PERSON = "There is no employee with the full name %1$s " + + "in the current displayed task list!"; + + public static final String MESSAGE_PERSON_TAGGED_TO_TASK = "Employee %1$s is already tagged to the task: "; + + private final Index targetIndex; + private final String name; + + /** + * Constructor to initialize a TagTaskCommand class with the given + * targetIndex and name. + * + * @param targetIndex Index of the Task to tag the employee + * @param name Name of the Employee to tag the Task to + */ + public TagTaskCommand(Index targetIndex, String name) { + requireAllNonNull(targetIndex, name); + this.targetIndex = targetIndex; + this.name = name; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownTaskList = model.getFilteredTaskList(); + List lastShownPersonList = model.getFilteredPersonList(); + + if (targetIndex.getZeroBased() >= lastShownTaskList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task taskToTagEmployee = lastShownTaskList.get(targetIndex.getZeroBased()); + + Person person = null; + + for (Person p : lastShownPersonList) { + if (p.getName().toString().equals(name)) { + person = p; + break; + } + } + + if (person == null) { + throw new CommandException(String.format(MESSAGE_NO_SUCH_PERSON, name) + "\n\n" + MESSAGE_USAGE); + } + + if (model.isEmployeeTaggedToTask(taskToTagEmployee, person)) { + throw new CommandException(String.format(MESSAGE_PERSON_TAGGED_TO_TASK, + person.getName().toString()) + taskToTagEmployee + "\n\n" + MESSAGE_USAGE); + } + + Task taggedEmployeeTask = model.tagEmployeeToTask(taskToTagEmployee, person); + model.increaseNumOfTasks(person); + + return new CommandResult(String.format(MESSAGE_TAG_TASK_SUCCESS, + person.getName().toString()) + taggedEmployeeTask); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof TagTaskCommand// instanceof handles nulls + && targetIndex.equals(((TagTaskCommand) other).targetIndex) + && name.equals(((TagTaskCommand) other).name)); + } +} diff --git a/src/main/java/manageezpz/logic/commands/TagTaskPriorityCommand.java b/src/main/java/manageezpz/logic/commands/TagTaskPriorityCommand.java new file mode 100644 index 00000000000..fe1fe979167 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/TagTaskPriorityCommand.java @@ -0,0 +1,69 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PRIORITY; + +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.task.Priority; +import manageezpz.model.task.Task; + +public class TagTaskPriorityCommand extends Command { + + public static final String COMMAND_WORD = "tagPriority"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Tags the specified priority to the task identified by the " + + "index number used in the displayed task list.\n" + + "Parameters: INDEX (must be a positive integer) " + + PREFIX_PRIORITY + "PRIORITY_VALUE " + "(must be either NONE/LOW/MEDIUM/HIGH)\n" + + "Example: " + COMMAND_WORD + " 1 " + PREFIX_PRIORITY + "HIGH"; + + public static final String MESSAGE_TAG_PRIORITY_SUCCESS = "Task tagged with %1$s priority: "; + + private final Index targetIndex; + private final Priority priority; + + /** + * Constructor to initialize a TagTaskPriorityCommand class with the given + * targetIndex and priority. + * + * @param targetIndex Index of the Task to tag the priority level + * @param priority Priority level of the Task + */ + public TagTaskPriorityCommand(Index targetIndex, Priority priority) { + requireAllNonNull(targetIndex, priority); + this.targetIndex = targetIndex; + this.priority = priority; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownList = model.getFilteredTaskList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task taskToTagPriority = lastShownList.get(targetIndex.getZeroBased()); + Task taggedPriorityTask = model.tagPriorityToTask(taskToTagPriority, priority); + + return new CommandResult(String.format(MESSAGE_TAG_PRIORITY_SUCCESS, priority.name()) + + taggedPriorityTask); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof TagTaskPriorityCommand// instanceof handles nulls + && targetIndex.equals(((TagTaskPriorityCommand) other).targetIndex) + && priority.equals(((TagTaskPriorityCommand) other).priority)); + } +} diff --git a/src/main/java/manageezpz/logic/commands/UnmarkTaskCommand.java b/src/main/java/manageezpz/logic/commands/UnmarkTaskCommand.java new file mode 100644 index 00000000000..889f77701f3 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/UnmarkTaskCommand.java @@ -0,0 +1,68 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.task.Task; + +/** + * Unmarks a task identified using its displayed index from the address book, + * i.e., changes the status back to not done. + */ +public class UnmarkTaskCommand extends Command { + + public static final String COMMAND_WORD = "unmarkTask"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Unmarks the task identified by the index number used in the displayed task list, " + + "which changes the status back to not done.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_UNMARK_TASK_SUCCESS = "Task set as not done yet: %1$s"; + + private final Index targetIndex; + + /** + * Constructor to initialize an instance of UnmarkTaskCommand class + * with the given targetIndex. + * + * @param targetIndex Index of the Task to be unmarked, i.e., changes the + * status back to not done + */ + public UnmarkTaskCommand(Index targetIndex) { + requireNonNull(targetIndex); + this.targetIndex = targetIndex; + } + + /** + * {@inheritDoc} + */ + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownList = model.getFilteredTaskList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task taskToUnmark = lastShownList.get(targetIndex.getZeroBased()); + Task unmarkedTask = model.unmarkTask(taskToUnmark); + + return new CommandResult(String.format(MESSAGE_UNMARK_TASK_SUCCESS, unmarkedTask)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UnmarkTaskCommand // instanceof handles nulls + && targetIndex.equals(((UnmarkTaskCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/manageezpz/logic/commands/UntagTaskCommand.java b/src/main/java/manageezpz/logic/commands/UntagTaskCommand.java new file mode 100644 index 00000000000..ddd6f0b19f2 --- /dev/null +++ b/src/main/java/manageezpz/logic/commands/UntagTaskCommand.java @@ -0,0 +1,95 @@ +package manageezpz.logic.commands; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; + +import java.util.List; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.model.Model; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; + +public class UntagTaskCommand extends Command { + + public static final String COMMAND_WORD = "untagTask"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Untags the specified employee from the task identified by the " + + "index number used in the displayed task list.\n" + + "Parameters: INDEX (must be a positive integer) " + + PREFIX_NAME + "EMPLOYEE_FULL_NAME\n" + + "Example: " + COMMAND_WORD + " 1 " + PREFIX_NAME + "Alex Yeoh"; + + public static final String MESSAGE_UNTAG_TASK_SUCCESS = "Employee %1$s is untagged from the task: "; + + public static final String MESSAGE_NO_SUCH_PERSON = "There is no employee with the full name %1$s " + + "in the current displayed task list!"; + + public static final String MESSAGE_PERSON_NOT_TAGGED_TO_TASK = "Employee %1$s is not tagged to the task: "; + + private final Index targetIndex; + private final String name; + + /** + * Constructor to initialize an UntagTaskCommand class with the given + * targetIndex and name. + * + * @param targetIndex Index of the Task to untag the employee + * @param name Name of the Employee to untag the Task from + */ + public UntagTaskCommand(Index targetIndex, String name) { + requireAllNonNull(targetIndex, name); + this.targetIndex = targetIndex; + this.name = name; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + List lastShownTaskList = model.getFilteredTaskList(); + List lastShownPersonList = model.getFilteredPersonList(); + + if (targetIndex.getZeroBased() >= lastShownTaskList.size()) { + throw new CommandException(String.format(MESSAGE_INVALID_TASK_DISPLAYED_INDEX, MESSAGE_USAGE)); + } + + Task taskToUntagEmployee = lastShownTaskList.get(targetIndex.getZeroBased()); + + Person person = null; + + for (Person p : lastShownPersonList) { + if (p.getName().toString().equals(name)) { + person = p; + break; + } + } + + if (person == null) { + throw new CommandException(String.format(MESSAGE_NO_SUCH_PERSON, name) + "\n\n" + MESSAGE_USAGE); + } + + if (!model.isEmployeeTaggedToTask(taskToUntagEmployee, person)) { + throw new CommandException(String.format(MESSAGE_PERSON_NOT_TAGGED_TO_TASK, + person.getName().toString()) + taskToUntagEmployee + "\n\n" + MESSAGE_USAGE); + } + + Task untaggedEmployeeTask = model.untagEmployeeFromTask(taskToUntagEmployee, person); + model.decreaseNumOfTasks(person); + + return new CommandResult(String.format(MESSAGE_UNTAG_TASK_SUCCESS, + person.getName().toString()) + untaggedEmployeeTask); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UntagTaskCommand// instanceof handles nulls + && targetIndex.equals(((UntagTaskCommand) other).targetIndex) + && name.equals(((UntagTaskCommand) other).name)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/manageezpz/logic/commands/exceptions/CommandException.java similarity index 83% rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java rename to src/main/java/manageezpz/logic/commands/exceptions/CommandException.java index a16bd14f2cd..c4c59339632 100644 --- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java +++ b/src/main/java/manageezpz/logic/commands/exceptions/CommandException.java @@ -1,4 +1,6 @@ -package seedu.address.logic.commands.exceptions; +package manageezpz.logic.commands.exceptions; + +import manageezpz.logic.commands.Command; /** * Represents an error which occurs during execution of a {@link Command}. diff --git a/src/main/java/manageezpz/logic/parser/AddDeadlineTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/AddDeadlineTaskCommandParser.java new file mode 100644 index 00000000000..2894db29ac1 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/AddDeadlineTaskCommandParser.java @@ -0,0 +1,62 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.commands.AddDeadlineTaskCommand.MESSAGE_USAGE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_BY_DATETIME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import java.util.stream.Stream; + +import manageezpz.logic.commands.AddDeadlineTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.task.Date; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Description; +import manageezpz.model.task.Time; + +public class AddDeadlineTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the AddDeadlineTaskCommand + * and returns an AddDeadlineTaskCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public AddDeadlineTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimapDeadline = + ArgumentTokenizer.tokenize(args, PREFIX_DESCRIPTION, PREFIX_BY_DATETIME); + + if (!arePrefixesPresent(argMultimapDeadline, PREFIX_DESCRIPTION, PREFIX_BY_DATETIME) + || !argMultimapDeadline.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + AddDeadlineTaskCommand.MESSAGE_USAGE)); + } + + try { + Description desc = ParserUtil.parseDescription(argMultimapDeadline.getValue(PREFIX_DESCRIPTION).get()); + + String byDateTime = argMultimapDeadline.getValue(PREFIX_BY_DATETIME).get(); + String[] parseByDateTime = byDateTime.split(" "); + + if (parseByDateTime.length != 2) { + throw new ParseException(MESSAGE_INVALID_COMMAND_FORMAT); + } + + Date date = ParserUtil.parseDate(parseByDateTime[0]); + Time time = ParserUtil.parseTime(parseByDateTime[1]); + + Deadline deadline = new Deadline(desc, date, time); + return new AddDeadlineTaskCommand(deadline); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + MESSAGE_USAGE); + } + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/manageezpz/logic/parser/AddEmployeeCommandParser.java b/src/main/java/manageezpz/logic/parser/AddEmployeeCommandParser.java new file mode 100644 index 00000000000..cc67d3783b4 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/AddEmployeeCommandParser.java @@ -0,0 +1,54 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EMAIL; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PHONE; + +import java.util.stream.Stream; + +import manageezpz.logic.commands.AddEmployeeCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.Person; +import manageezpz.model.person.Phone; + +/** + * Parses input arguments and creates a new AddEmployeeCommand object + */ +public class AddEmployeeCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the AddEmployeeCommand + * and returns an AddEmployeeCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public AddEmployeeCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL); + + if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + AddEmployeeCommand.MESSAGE_USAGE)); + } + + Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); + Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); + Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); + + Person person = new Person(name, phone, email, 0); + + return new AddEmployeeCommand(person); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } + +} diff --git a/src/main/java/manageezpz/logic/parser/AddEventTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/AddEventTaskCommandParser.java new file mode 100644 index 00000000000..5dc9c2135fe --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/AddEventTaskCommandParser.java @@ -0,0 +1,67 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_TIME_RANGE; +import static manageezpz.logic.commands.AddEventTaskCommand.MESSAGE_USAGE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_AT_DATETIME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import java.util.stream.Stream; + +import manageezpz.logic.commands.AddEventTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.task.Date; +import manageezpz.model.task.Description; +import manageezpz.model.task.Event; +import manageezpz.model.task.Time; + +public class AddEventTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the AddEventTaskCommand + * and returns an AddEventTaskCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public AddEventTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimapEvent = + ArgumentTokenizer.tokenize(args, PREFIX_DESCRIPTION, PREFIX_AT_DATETIME); + + if (!arePrefixesPresent(argMultimapEvent, PREFIX_DESCRIPTION, PREFIX_AT_DATETIME) + || !argMultimapEvent.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, MESSAGE_USAGE)); + } + + try { + Description desc = ParserUtil.parseDescription(argMultimapEvent.getValue(PREFIX_DESCRIPTION).get()); + + String atDateTime = argMultimapEvent.getValue(PREFIX_AT_DATETIME).get(); + String[] parseAtDateTime = atDateTime.split(" "); + + if (parseAtDateTime.length != 3) { + throw new ParseException(MESSAGE_INVALID_COMMAND_FORMAT); + } + + Date date = ParserUtil.parseDate(parseAtDateTime[0]); + Time startTime = ParserUtil.parseTime(parseAtDateTime[1]); + Time endTime = ParserUtil.parseTime(parseAtDateTime[2]); + + if (endTime.getParsedTime().compareTo(startTime.getParsedTime()) < 1) { + throw new ParseException(MESSAGE_INVALID_TIME_RANGE); + } + + Event event = new Event(desc, date, startTime, endTime); + return new AddEventTaskCommand(event); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + MESSAGE_USAGE); + } + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/manageezpz/logic/parser/AddTodoTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/AddTodoTaskCommandParser.java new file mode 100644 index 00000000000..f608151b338 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/AddTodoTaskCommandParser.java @@ -0,0 +1,47 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.commands.AddTodoTaskCommand.MESSAGE_USAGE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import java.util.stream.Stream; + +import manageezpz.logic.commands.AddTodoTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.task.Description; +import manageezpz.model.task.Todo; + +public class AddTodoTaskCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the AddEmployeeCommand + * and returns an AddEmployeeCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public AddTodoTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimapTodo = + ArgumentTokenizer.tokenize(args, PREFIX_DESCRIPTION); + + if (!arePrefixesPresent(argMultimapTodo, PREFIX_DESCRIPTION) + || !argMultimapTodo.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + AddTodoTaskCommand.MESSAGE_USAGE)); + } + + try { + Description desc = ParserUtil.parseDescription(argMultimapTodo.getValue(PREFIX_DESCRIPTION).get()); + Todo todoTask = new Todo(desc); + return new AddTodoTaskCommand(todoTask); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + MESSAGE_USAGE); + } + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } + +} diff --git a/src/main/java/manageezpz/logic/parser/AddressBookParser.java b/src/main/java/manageezpz/logic/parser/AddressBookParser.java new file mode 100644 index 00000000000..ae492036753 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/AddressBookParser.java @@ -0,0 +1,126 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import manageezpz.logic.commands.AddDeadlineTaskCommand; +import manageezpz.logic.commands.AddEmployeeCommand; +import manageezpz.logic.commands.AddEventTaskCommand; +import manageezpz.logic.commands.AddTodoTaskCommand; +import manageezpz.logic.commands.ClearCommand; +import manageezpz.logic.commands.Command; +import manageezpz.logic.commands.DeleteEmployeeCommand; +import manageezpz.logic.commands.DeleteTaskCommand; +import manageezpz.logic.commands.EditEmployeeCommand; +import manageezpz.logic.commands.EditTaskCommand; +import manageezpz.logic.commands.ExitCommand; +import manageezpz.logic.commands.FindEmployeeCommand; +import manageezpz.logic.commands.FindTaskCommand; +import manageezpz.logic.commands.HelpCommand; +import manageezpz.logic.commands.ListEmployeeCommand; +import manageezpz.logic.commands.ListTaskCommand; +import manageezpz.logic.commands.MarkTaskCommand; +import manageezpz.logic.commands.TagTaskCommand; +import manageezpz.logic.commands.TagTaskPriorityCommand; +import manageezpz.logic.commands.UnmarkTaskCommand; +import manageezpz.logic.commands.UntagTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses user input. + */ +public class AddressBookParser { + + /** + * 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 + * @throws ParseException if the user input does not conform the expected format + */ + public Command parseCommand(String userInput) throws ParseException { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + + if (!matcher.matches()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + final String arguments = matcher.group("arguments"); + + switch (commandWord) { + + case AddEmployeeCommand.COMMAND_WORD: + return new AddEmployeeCommandParser().parse(arguments); + + case EditEmployeeCommand.COMMAND_WORD: + return new EditEmployeeCommandParser().parse(arguments); + + case DeleteEmployeeCommand.COMMAND_WORD: + return new DeleteEmployeeCommandParser().parse(arguments); + + case DeleteTaskCommand.COMMAND_WORD: + return new DeleteTaskCommandParser().parse(arguments); + + case ClearCommand.COMMAND_WORD: + return new ClearCommand(); + + case FindTaskCommand.COMMAND_WORD: + return new FindTaskCommandParser().parse(arguments); + + case FindEmployeeCommand.COMMAND_WORD: + return new FindEmployeeCommandParser().parse(arguments); + + case ListTaskCommand.COMMAND_WORD: + return new ListTaskCommand(); + + case ListEmployeeCommand.COMMAND_WORD: + return new ListEmployeeCommand(); + + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); + + case HelpCommand.COMMAND_WORD: + return new HelpCommand(); + + case AddTodoTaskCommand.COMMAND_WORD: + return new AddTodoTaskCommandParser().parse(arguments); + + case AddEventTaskCommand.COMMAND_WORD: + return new AddEventTaskCommandParser().parse(arguments); + + case AddDeadlineTaskCommand.COMMAND_WORD: + return new AddDeadlineTaskCommandParser().parse(arguments); + + case MarkTaskCommand.COMMAND_WORD: + return new MarkTaskCommandParser().parse(arguments); + + case UnmarkTaskCommand.COMMAND_WORD: + return new UnmarkTaskCommandParser().parse(arguments); + + case TagTaskCommand.COMMAND_WORD: + return new TagTaskCommandParser().parse(arguments); + + case UntagTaskCommand.COMMAND_WORD: + return new UntagTaskCommandParser().parse(arguments); + + case TagTaskPriorityCommand.COMMAND_WORD: + return new TagTaskPriorityCommandParser().parse(arguments); + + case EditTaskCommand.COMMAND_WORD: + return new EditTaskCommandParser().parse(arguments); + + default: + throw new ParseException(MESSAGE_UNKNOWN_COMMAND); + } + } + +} diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/manageezpz/logic/parser/ArgumentMultimap.java similarity index 94% rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java rename to src/main/java/manageezpz/logic/parser/ArgumentMultimap.java index 954c8e18f8e..bc5baeecc51 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java +++ b/src/main/java/manageezpz/logic/parser/ArgumentMultimap.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package manageezpz.logic.parser; import java.util.ArrayList; import java.util.HashMap; @@ -57,4 +57,9 @@ public List getAllValues(Prefix prefix) { public String getPreamble() { return getValue(new Prefix("")).orElse(""); } + + + public boolean isPrefixExist(Prefix prefix) { + return argMultimap.containsKey(prefix); + } } diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/manageezpz/logic/parser/ArgumentTokenizer.java similarity index 99% rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java rename to src/main/java/manageezpz/logic/parser/ArgumentTokenizer.java index 5c9aebfa488..cd4b84f8ed3 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java +++ b/src/main/java/manageezpz/logic/parser/ArgumentTokenizer.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package manageezpz.logic.parser; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/manageezpz/logic/parser/CliSyntax.java b/src/main/java/manageezpz/logic/parser/CliSyntax.java new file mode 100644 index 00000000000..e2505c18bee --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/CliSyntax.java @@ -0,0 +1,23 @@ +package manageezpz.logic.parser; + +/** + * Contains Command Line Interface (CLI) syntax definitions common to multiple commands + */ +public class CliSyntax { + + /* Prefix definitions */ + public static final Prefix PREFIX_NAME = new Prefix("n/"); + public static final Prefix PREFIX_PHONE = new Prefix("p/"); + public static final Prefix PREFIX_EMAIL = new Prefix("e/"); + public static final Prefix PREFIX_DESCRIPTION = new Prefix("desc/"); + public static final Prefix PREFIX_TODO = new Prefix("todo/"); + public static final Prefix PREFIX_DEADLINE = new Prefix("deadline/"); + public static final Prefix PREFIX_EVENT = new Prefix("event/"); + public static final Prefix PREFIX_TODAY = new Prefix("today/"); + public static final Prefix PREFIX_BY_DATETIME = new Prefix("by/"); + public static final Prefix PREFIX_AT_DATETIME = new Prefix("at/"); + public static final Prefix PREFIX_DATE = new Prefix("date/"); + public static final Prefix PREFIX_PRIORITY = new Prefix("priority/"); + public static final Prefix PREFIX_ASSIGNEES = new Prefix("assignees/"); + public static final Prefix PREFIX_IS_MARKED = new Prefix("isMarked/"); +} diff --git a/src/main/java/manageezpz/logic/parser/DeleteEmployeeCommandParser.java b/src/main/java/manageezpz/logic/parser/DeleteEmployeeCommandParser.java new file mode 100644 index 00000000000..1a06f673d98 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/DeleteEmployeeCommandParser.java @@ -0,0 +1,34 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.DeleteEmployeeCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new DeleteEmployeeCommand object + */ +public class DeleteEmployeeCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the DeleteEmployeeCommand + * and returns a DeleteEmployeeCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteEmployeeCommand parse(String args) throws ParseException { + // Invalid command if args after trimming is empty or contains whitespaces + if (args.trim().isEmpty() || args.trim().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + DeleteEmployeeCommand.MESSAGE_USAGE)); + } + + try { + Index index = ParserUtil.parseIndex(args); + return new DeleteEmployeeCommand(index); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + DeleteEmployeeCommand.MESSAGE_USAGE, pe); + } + } +} diff --git a/src/main/java/manageezpz/logic/parser/DeleteTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/DeleteTaskCommandParser.java new file mode 100644 index 00000000000..e2ab774dad2 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/DeleteTaskCommandParser.java @@ -0,0 +1,34 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.DeleteTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new DeleteTaskCommand object + */ +public class DeleteTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the DeleteTaskCommand + * and returns a DeleteTaskCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteTaskCommand parse(String args) throws ParseException { + // Invalid command if args after trimming is empty or contains whitespaces + if (args.trim().isEmpty() || args.trim().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + DeleteTaskCommand.MESSAGE_USAGE)); + } + + try { + Index index = ParserUtil.parseIndex(args); + return new DeleteTaskCommand(index); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + DeleteTaskCommand.MESSAGE_USAGE, pe); + } + } +} diff --git a/src/main/java/manageezpz/logic/parser/EditEmployeeCommandParser.java b/src/main/java/manageezpz/logic/parser/EditEmployeeCommandParser.java new file mode 100644 index 00000000000..5bc710bf17a --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/EditEmployeeCommandParser.java @@ -0,0 +1,63 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_FIELD_NOT_EDITED; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EMAIL; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PHONE; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.EditEmployeeCommand; +import manageezpz.logic.commands.EditEmployeeCommand.EditEmployeeDescriptor; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new EditEmployeeCommand object + */ +public class EditEmployeeCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the EditEmployeeCommand + * and returns an EditEmployeeCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public EditEmployeeCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL); + + // Invalid command if getPreamble() is empty or contains other whitespaces + if (argMultimap.getPreamble().isEmpty() || argMultimap.getPreamble().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + EditEmployeeCommand.MESSAGE_USAGE)); + } + + Index index; + + EditEmployeeDescriptor editEmployeeDescriptor = new EditEmployeeCommand.EditEmployeeDescriptor(); + + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + + if (argMultimap.getValue(PREFIX_NAME).isPresent()) { + editEmployeeDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get())); + } + + if (argMultimap.getValue(PREFIX_PHONE).isPresent()) { + editEmployeeDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get())); + } + + if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { + editEmployeeDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); + } + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + EditEmployeeCommand.MESSAGE_USAGE, pe); + } + + if (!editEmployeeDescriptor.isAnyFieldEdited()) { + throw new ParseException(MESSAGE_FIELD_NOT_EDITED + EditEmployeeCommand.MESSAGE_USAGE); + } + + return new EditEmployeeCommand(index, editEmployeeDescriptor); + } +} diff --git a/src/main/java/manageezpz/logic/parser/EditTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/EditTaskCommandParser.java new file mode 100644 index 00000000000..0ac4840dc7b --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/EditTaskCommandParser.java @@ -0,0 +1,95 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_FIELD_NOT_EDITED; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_AT_DATETIME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DATE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; + +import java.util.HashMap; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.EditTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new EditTaskCommand object. + */ +public class EditTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the EditTaskCommand + * and returns a EditTaskCommand object for execution. + * + * @throws ParseException if the user input does not conform to the expected format + */ + @Override + public EditTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_DESCRIPTION, PREFIX_AT_DATETIME, PREFIX_DATE); + + // Invalid command if getPreamble() is empty or contains whitespaces + if (argMultimap.getPreamble().isEmpty() || argMultimap.getPreamble().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + EditTaskCommand.MESSAGE_USAGE)); + } + + Index index; + + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + EditTaskCommand.MESSAGE_USAGE, pe); + } + + if (argMultimap.getValue(PREFIX_DESCRIPTION).isEmpty() + && argMultimap.getValue(PREFIX_DATE).isEmpty() + && argMultimap.getValue(PREFIX_AT_DATETIME).isEmpty()) { + throw new ParseException(MESSAGE_FIELD_NOT_EDITED + EditTaskCommand.MESSAGE_USAGE); + } + + String desc = argMultimap.getValue(PREFIX_DESCRIPTION).orElse(""); + String date = argMultimap.getValue(PREFIX_DATE).orElse(""); + String time = argMultimap.getValue(PREFIX_AT_DATETIME).orElse(""); + HashMap prefixStatusHash = prefixStatusCheck(argMultimap); + + return new EditTaskCommand(index, desc, date, time, prefixStatusHash); + } + + /** + * Initialize a hashmap that contains the status of a prefix. + * By status, it means whether a prefix has been inputted by a user or not. + */ + private HashMap initPrefixStatusHash() { + HashMap prefixStatusHash = new HashMap<>(); + prefixStatusHash.put("description", true); + prefixStatusHash.put("date", true); + prefixStatusHash.put("datetime", true); + return prefixStatusHash; + } + + /** + * Check if a prefix has been inputted by a user or not. + * If yes, the boolean value of the corresponding prefix is true. + * Else, it is false. + * Note that it only checks if the prefix has been inputted. + * It does not check if there's a value attached to the prefix. + */ + private HashMap prefixStatusCheck (ArgumentMultimap argMultimap) { + HashMap prefixStatusHash = initPrefixStatusHash(); + + if (argMultimap.getValue(PREFIX_DESCRIPTION).isEmpty()) { + prefixStatusHash.replace("description", false); + } + + if (argMultimap.getValue(PREFIX_DATE).isEmpty()) { + prefixStatusHash.replace("date", false); + } + + if (argMultimap.getValue(PREFIX_AT_DATETIME).isEmpty()) { + prefixStatusHash.replace("datetime", false); + } + + return prefixStatusHash; + } +} diff --git a/src/main/java/manageezpz/logic/parser/FindEmployeeCommandParser.java b/src/main/java/manageezpz/logic/parser/FindEmployeeCommandParser.java new file mode 100644 index 00000000000..ed62812b678 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/FindEmployeeCommandParser.java @@ -0,0 +1,142 @@ +package manageezpz.logic.parser; + +import static manageezpz.logic.parser.CliSyntax.PREFIX_EMAIL; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PHONE; + +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; +import java.util.stream.Stream; + +import manageezpz.commons.core.LogsCenter; +import manageezpz.commons.core.Messages; +import manageezpz.logic.commands.FindEmployeeCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.PersonMultiplePredicate; +import manageezpz.model.person.Phone; + +/** + * Checks if the options are valid for finding employees. + */ +public class FindEmployeeCommandParser implements Parser { + private static final Prefix[] PERSON_PROPERTIES = {PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL}; + private static final Logger logger = LogsCenter.getLogger(FindEmployeeCommandParser.class); + + private String errorMessage = ""; + private boolean hasError = false; + + /** + * {@inheritDoc} + */ + @Override + public FindEmployeeCommand parse(String userInput) throws ParseException { + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PERSON_PROPERTIES); + + checkIfHaveAtLeastOneOption(argMultimap); + List names = getPersonName(argMultimap); + String phone = getPersonPhone(argMultimap); + String email = getPersonEmail(argMultimap); + + if (hasError) { + String finalMessage = errorMessage + FindEmployeeCommand.MESSAGE_USAGE; + String displayedMessage = String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND, finalMessage); + throw new ParseException(displayedMessage); + } else { + PersonMultiplePredicate predicate = new PersonMultiplePredicate(names, phone, email); + return new FindEmployeeCommand(predicate); + } + } + + private void checkIfHaveAtLeastOneOption(ArgumentMultimap argMultiMap) { + String noOptionsMessage = "No option found"; + if (!isAtLeastOnePrefixPresent(argMultiMap, PERSON_PROPERTIES) || !argMultiMap.getPreamble().isEmpty()) { + logger.warning(noOptionsMessage); + addErrorMessage(FindEmployeeCommand.NO_OPTIONS); + } + } + + private List getPersonName(ArgumentMultimap argMultimap) { + String nameMessage = "Names:"; + List names = null; + if (argMultimap.isPrefixExist(PREFIX_NAME)) { + String nameArgumentString = argMultimap.getValue(PREFIX_NAME).get().trim(); + String[] nameArguments = nameArgumentString.split("\\s+"); + logger.info(String.join(" ", nameMessage, nameArguments.toString())); + names = checkIfAllNamesValid(nameArguments); + } + return names; + } + + private List checkIfAllNamesValid(String[] nameArguments) { + String invalidNameMessage = "Invalid name."; + List names = null; + boolean isValid = Arrays.stream(nameArguments).allMatch(name -> Name.isValidName(name)); + if (!isValid) { + logger.warning(invalidNameMessage); + addErrorMessage(FindEmployeeCommand.INVALID_NAME); + } else { + names = Arrays.asList(nameArguments); + } + return names; + } + + private String getPersonPhone(ArgumentMultimap argMultimap) { + String phoneMessage = "Phone:"; + String phone = null; + if (argMultimap.isPrefixExist(PREFIX_PHONE)) { + phone = argMultimap.getValue(PREFIX_PHONE).get(); + logger.info(String.join(" ", phoneMessage, phone)); + checkIfPhoneValid(phone); + } + return phone; + } + + private void checkIfPhoneValid(String phone) { + String invalidPhoneMessage = "Invalid phone detected"; + boolean isValidPhone = Phone.isValidPhone(phone); + if (!isValidPhone) { + logger.warning(invalidPhoneMessage); + addErrorMessage(FindEmployeeCommand.INVALID_PHONE); + } + } + + private String getPersonEmail(ArgumentMultimap argMultimap) { + String emailMessage = "Email:"; + String email = null; + if (argMultimap.isPrefixExist(PREFIX_EMAIL)) { + email = argMultimap.getValue(PREFIX_EMAIL).get(); + logger.info(String.join(" ", emailMessage, email)); + checkIfEmailIsValid(email); + } + return email; + } + + private void checkIfEmailIsValid(String email) { + String invalidEmailMessage = "Invalid email"; + boolean isValidEmail = Email.isValidEmail(email); + if (!isValidEmail) { + logger.warning(invalidEmailMessage); + addErrorMessage(FindEmployeeCommand.INVALID_EMAIL); + } + } + + /** + * Collates all the errors and shows the UI after processing all properties. + * @param errorMessage Error message from each checking to be added to the overall error message. + */ + private void addErrorMessage(String errorMessage) { + hasError = true; + this.errorMessage = this.errorMessage + errorMessage; + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean isAtLeastOnePrefixPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).anyMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/manageezpz/logic/parser/FindTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/FindTaskCommandParser.java new file mode 100644 index 00000000000..b074c759b9e --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/FindTaskCommandParser.java @@ -0,0 +1,246 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_ASSIGNEES; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DATE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DEADLINE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_DESCRIPTION; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EVENT; +import static manageezpz.logic.parser.CliSyntax.PREFIX_IS_MARKED; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PRIORITY; +import static manageezpz.logic.parser.CliSyntax.PREFIX_TODO; + +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import manageezpz.commons.core.LogsCenter; +import manageezpz.logic.commands.FindTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.person.Name; +import manageezpz.model.task.Date; +import manageezpz.model.task.Description; +import manageezpz.model.task.Priority; +import manageezpz.model.task.TaskMultiplePredicate; + +/** + * Subclass of FindCommandParser which check if the options are valid for finding tasks. + */ +public class FindTaskCommandParser implements Parser { + private static final Prefix[] TASK_TYPES = {PREFIX_TODO, PREFIX_DEADLINE, PREFIX_EVENT}; + private static final Prefix[] VALID_OPTIONS = {PREFIX_TODO, PREFIX_DEADLINE, PREFIX_EVENT, PREFIX_DATE, + PREFIX_DESCRIPTION, PREFIX_PRIORITY, PREFIX_ASSIGNEES, PREFIX_IS_MARKED}; + private static final Logger logger = LogsCenter.getLogger(FindTaskCommandParser.class); + + private String errorMessage = ""; + private boolean hasError = false; + + /** + * {@inheritDoc} + */ + public FindTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultiMap = ArgumentTokenizer.tokenize(args, VALID_OPTIONS); + + checkIfHaveAtLeastOneOption(argMultiMap); + Prefix taskType = getPrefix(argMultiMap); + List descriptions = getDescriptions(argMultiMap); + Date date = getTaskDate(argMultiMap); + Priority priority = getTaskPriority(argMultiMap); + String assignee = getAssignee(argMultiMap); + Boolean isMarked = getIsMarked(argMultiMap); + + checkIfTodoAndDateTogether(argMultiMap, taskType); + + if (hasError) { + String finalMessage = errorMessage + FindTaskCommand.MESSAGE_USAGE; + String displayedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, finalMessage); + throw new ParseException(displayedMessage); + } else { + return new FindTaskCommand(new TaskMultiplePredicate( + taskType, descriptions, date, priority, assignee, isMarked)); + } + } + + private void checkIfHaveAtLeastOneOption(ArgumentMultimap argMultiMap) { + String noOptionEnteredMessage = "No option entered for find task command."; + + if (!isAtLeastOnePrefixPresent(argMultiMap, VALID_OPTIONS) || !argMultiMap.getPreamble().isEmpty()) { + logger.warning(noOptionEnteredMessage); + addErrorMessage(FindTaskCommand.NO_OPTIONS); + } + } + + private void checkIfTodoAndDateTogether(ArgumentMultimap argMultiMapProperties, Prefix taskTypes) { + boolean isContainsTodo = taskTypes instanceof Prefix && taskTypes.equals(PREFIX_TODO); + String todoAndDateOptionTogetherMessage = "todo/ and date/ are together"; + + if (isContainsTodo && argMultiMapProperties.isPrefixExist(PREFIX_DATE)) { + logger.warning(todoAndDateOptionTogetherMessage); + addErrorMessage(FindTaskCommand.TODO_AND_DATE_OPTION_TOGETHER); + } + } + + private Prefix getPrefix(ArgumentMultimap argMultiMap) { + List currentPrefixes = Arrays.stream(TASK_TYPES) + .filter(prefix -> argMultiMap.isPrefixExist(prefix)).collect(Collectors.toList()); + String prefixEnteredMessage = "Prefix entered:"; + + if (!currentPrefixes.isEmpty()) { + logger.info(String.join(" ", prefixEnteredMessage, currentPrefixes.toString())); + } + + if (currentPrefixes.size() > 1) { + // If the user enters more than 1 task type + String moreThanOneTaskTypeMessage = "More than one task type entered as options"; + logger.warning(moreThanOneTaskTypeMessage); + addErrorMessage(FindTaskCommand.MORE_THAN_ONE_TASK_TYPE); + return null; + } else if (currentPrefixes.isEmpty()) { + return null; + } else { + Prefix currentPrefix = currentPrefixes.get(0); + return currentPrefix; + } + } + + private List getDescriptions(ArgumentMultimap argMultiMap) { + String namesMessage = "Description:"; + List descriptions = null; + if (argMultiMap.isPrefixExist(PREFIX_DESCRIPTION)) { + String descriptionString = argMultiMap.getValue(PREFIX_DESCRIPTION).get(); + descriptions = List.of(descriptionString.split("\\s+")); + logger.info(String.join(" ", namesMessage, descriptions.toString())); + checkIfValidDescription(descriptions); + } + return descriptions; + } + + private void checkIfValidDescription(List description) { + String invalidDescriptionFoundMessage = "Invalid Description found."; + boolean isValid = description.stream().allMatch(name -> Description.isValidDescription(name)); + if (!isValid) { + logger.warning(invalidDescriptionFoundMessage); + addErrorMessage(FindTaskCommand.INVALID_DESCRIPTION); + } + } + + private Date getTaskDate(ArgumentMultimap argMultiMap) { + String dateMessage = "Date:"; + Date date = null; + if (argMultiMap.isPrefixExist(PREFIX_DATE)) { + String dateString = argMultiMap.getValue(PREFIX_DATE).get().trim(); + logger.info(String.join(" ", dateMessage, dateString)); + boolean isDateValid = checkIfDateIsValid(dateString); + if (isDateValid) { + date = new Date(dateString); + } + } + return date; + } + + private boolean checkIfDateIsValid(String dateString) { + String invalidDateMessage = "Invalid date entered"; + boolean isValidDate = Date.isValidDate(dateString); + if (!isValidDate) { + logger.warning(invalidDateMessage); + addErrorMessage(FindTaskCommand.INVALID_DATE); + return false; + } + return true; + } + + private Priority getTaskPriority(ArgumentMultimap argMultiMap) { + String prioritySelectedMessage = "Priority selected:"; + Priority priority = null; + if (argMultiMap.isPrefixExist(PREFIX_PRIORITY)) { + String priorityString = argMultiMap.getValue(PREFIX_PRIORITY).get().trim().toUpperCase(); + logger.info(String.join(" ", prioritySelectedMessage, priorityString)); + priority = checkPriority(priorityString); + } + return priority; + } + + private Priority checkPriority(String priorityString) { + String invalidPriorityStringMessage = "Invalid Priority String"; + switch (priorityString) { + case "HIGH": + return Priority.HIGH; + case "MEDIUM": + return Priority.MEDIUM; + case "LOW": + return Priority.LOW; + case "NONE": + return Priority.NONE; + default: + logger.warning(invalidPriorityStringMessage); + addErrorMessage(FindTaskCommand.INVALID_PRIORITY); + return null; + } + } + + private String getAssignee(ArgumentMultimap argMultiMap) { + String assigneeMessage = "Assignee:"; + String assignee = null; + if (argMultiMap.isPrefixExist(PREFIX_ASSIGNEES)) { + assignee = argMultiMap.getValue(PREFIX_ASSIGNEES).get().trim(); + logger.info(String.join(" ", assigneeMessage, assignee)); + checkedIfNameValid(assignee); + } + return assignee; + } + + private void checkedIfNameValid(String assignee) { + String invalidNameMessage = "Invalid name"; + boolean isNameValid = Name.isValidName(assignee); + if (!isNameValid) { + logger.warning(invalidNameMessage); + addErrorMessage(FindTaskCommand.INVALID_ASSIGNEE); + } + } + + private Boolean getIsMarked(ArgumentMultimap argMultiMap) { + String booleanMessage = "Boolean entered:"; + Boolean isMarked = null; + if (argMultiMap.isPrefixExist(PREFIX_IS_MARKED)) { + String booleanString = argMultiMap.getValue(PREFIX_IS_MARKED).get().trim().toLowerCase(); + logger.info(String.join(" ", booleanMessage, booleanString)); + boolean isEitherTrueOrFalse = checkIfEitherTrueOrFalse(booleanString); + if (isEitherTrueOrFalse) { + isMarked = Boolean.valueOf(booleanString); + } + } + return isMarked; + } + + private boolean checkIfEitherTrueOrFalse(String booleanString) { + String invalidBooleanMessage = "Invalid boolean"; + if (booleanString.equals("true") || booleanString.equals("false")) { + return true; + } else if (!booleanString.equals("true") && !booleanString.equals("false")) { + logger.warning(invalidBooleanMessage); + addErrorMessage(FindTaskCommand.INVALID_BOOLEAN); + return false; + } + assert false : "Error in checkIfEitherTrueOrFalse"; + return false; + } + + /** + * Collates all the errors and shows the UI after processing all properties. + * @param errorMessage Error message from each checking to be added to the overall error message. + */ + private void addErrorMessage(String errorMessage) { + hasError = true; + this.errorMessage = this.errorMessage + errorMessage; + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean isAtLeastOnePrefixPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).anyMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/manageezpz/logic/parser/MarkTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/MarkTaskCommandParser.java new file mode 100644 index 00000000000..62ad9351d5b --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/MarkTaskCommandParser.java @@ -0,0 +1,34 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.MarkTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new MarkTaskCommand object + */ +public class MarkTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the MarkTaskCommand + * and returns a MarkTaskCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public MarkTaskCommand parse(String args) throws ParseException { + // Invalid command if args after trimming is empty or contains whitespaces + if (args.trim().isEmpty() || args.trim().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + MarkTaskCommand.MESSAGE_USAGE)); + } + + try { + Index index = ParserUtil.parseIndex(args); + return new MarkTaskCommand(index); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + MarkTaskCommand.MESSAGE_USAGE, pe); + } + } +} diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/manageezpz/logic/parser/Parser.java similarity index 72% rename from src/main/java/seedu/address/logic/parser/Parser.java rename to src/main/java/manageezpz/logic/parser/Parser.java index d6551ad8e3f..07a31a42894 100644 --- a/src/main/java/seedu/address/logic/parser/Parser.java +++ b/src/main/java/manageezpz/logic/parser/Parser.java @@ -1,7 +1,7 @@ -package seedu.address.logic.parser; +package manageezpz.logic.parser; -import seedu.address.logic.commands.Command; -import seedu.address.logic.parser.exceptions.ParseException; +import manageezpz.logic.commands.Command; +import manageezpz.logic.parser.exceptions.ParseException; /** * Represents a Parser that is able to parse user input into a {@code Command} of type {@code T}. diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/manageezpz/logic/parser/ParserUtil.java similarity index 57% rename from src/main/java/seedu/address/logic/parser/ParserUtil.java rename to src/main/java/manageezpz/logic/parser/ParserUtil.java index b117acb9c55..794f208b480 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/manageezpz/logic/parser/ParserUtil.java @@ -1,26 +1,23 @@ -package seedu.address.logic.parser; +package manageezpz.logic.parser; import static java.util.Objects.requireNonNull; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import seedu.address.commons.core.index.Index; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.parser.exceptions.ParseException; -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 manageezpz.commons.core.index.Index; +import manageezpz.commons.util.StringUtil; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.Phone; +import manageezpz.model.task.Date; +import manageezpz.model.task.Description; +import manageezpz.model.task.Time; /** * Contains utility methods used for parsing strings in the various *Parser classes. */ public class ParserUtil { - public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer."; + public static final String MESSAGE_INVALID_INDEX = "Index specified is not a non-zero unsigned integer."; /** * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be @@ -65,21 +62,6 @@ public static Phone parsePhone(String phone) throws ParseException { return new Phone(trimmedPhone); } - /** - * Parses a {@code String address} into an {@code Address}. - * Leading and trailing whitespaces will be trimmed. - * - * @throws ParseException if the given {@code address} is invalid. - */ - public static Address parseAddress(String address) throws ParseException { - requireNonNull(address); - String trimmedAddress = address.trim(); - if (!Address.isValidAddress(trimmedAddress)) { - throw new ParseException(Address.MESSAGE_CONSTRAINTS); - } - return new Address(trimmedAddress); - } - /** * Parses a {@code String email} into an {@code Email}. * Leading and trailing whitespaces will be trimmed. @@ -96,29 +78,46 @@ public static Email parseEmail(String email) throws ParseException { } /** - * Parses a {@code String tag} into a {@code Tag}. - * Leading and trailing whitespaces will be trimmed. - * - * @throws ParseException if the given {@code tag} is invalid. + * Parses a {@code String date} into a {@code Date}. + * Supports multiple formatted patterns. + * @param date + * @return a {@code Date} object. + * @throws ParseException + */ + public static Date parseDate(String date) throws ParseException { + requireNonNull(date); + if (!Date.isValidDate(date)) { + throw new ParseException(Date.MESSAGE_CONSTRAINTS); + } + return new Date(date); + } + + /** + * Parses a {@code String time} into a {@code Time}. + * @param time + * @return a {@code Time} object. + * @throws ParseException */ - public static Tag parseTag(String tag) throws ParseException { - requireNonNull(tag); - String trimmedTag = tag.trim(); - if (!Tag.isValidTagName(trimmedTag)) { - throw new ParseException(Tag.MESSAGE_CONSTRAINTS); + public static Time parseTime(String time) throws ParseException { + requireNonNull(time); + if (!Time.isValidTime(time)) { + throw new ParseException(Time.MESSAGE_CONSTRAINTS); } - return new Tag(trimmedTag); + return new Time(time); } /** - * Parses {@code Collection tags} into a {@code Set}. + * Parses a {@code String description} into an {@code Description}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code description} is invalid. */ - public static Set parseTags(Collection tags) throws ParseException { - requireNonNull(tags); - final Set tagSet = new HashSet<>(); - for (String tagName : tags) { - tagSet.add(parseTag(tagName)); + public static Description parseDescription(String description) throws ParseException { + requireNonNull(description); + String trimmedDescription = description.trim(); + if (!Description.isValidDescription(trimmedDescription)) { + throw new ParseException(Description.MESSAGE_CONSTRAINTS); } - return tagSet; + return new Description(trimmedDescription); } } diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/manageezpz/logic/parser/Prefix.java similarity index 95% rename from src/main/java/seedu/address/logic/parser/Prefix.java rename to src/main/java/manageezpz/logic/parser/Prefix.java index c859d5fa5db..eda296bc100 100644 --- a/src/main/java/seedu/address/logic/parser/Prefix.java +++ b/src/main/java/manageezpz/logic/parser/Prefix.java @@ -1,4 +1,4 @@ -package seedu.address.logic.parser; +package manageezpz.logic.parser; /** * A prefix that marks the beginning of an argument in an arguments string. diff --git a/src/main/java/manageezpz/logic/parser/TagTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/TagTaskCommandParser.java new file mode 100644 index 00000000000..7b35381013c --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/TagTaskCommandParser.java @@ -0,0 +1,69 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_EMPTY_NAME; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; + +import java.util.stream.Stream; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.TagTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +public class TagTaskCommandParser implements Parser { + + public static final String MESSAGE_TAG_EMPLOYEE_TO_TASK_INSTRUCTIONS = + "Tag an employee to a task by specifying prefix n/ followed by the employee's full name!\n\n%1$s"; + + /** + * Parses the given {@code String} of arguments in the context of the TagTaskCommand + * and returns an TagTaskCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public TagTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimapTagTask = ArgumentTokenizer.tokenize(args, PREFIX_NAME); + + // Invalid command if getPreamble() is empty + if (argMultimapTagTask.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + TagTaskCommand.MESSAGE_USAGE)); + } + + // Invalid command if getPreamble() contains whitespaces + if (argMultimapTagTask.getPreamble().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT + " " + + MESSAGE_TAG_EMPLOYEE_TO_TASK_INSTRUCTIONS, TagTaskCommand.MESSAGE_USAGE)); + } + + Index index; + + try { + index = ParserUtil.parseIndex(argMultimapTagTask.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + TagTaskCommand.MESSAGE_USAGE, pe); + } + + if (!arePrefixesPresent(argMultimapTagTask, PREFIX_NAME)) { + throw new ParseException(String.format(MESSAGE_TAG_EMPLOYEE_TO_TASK_INSTRUCTIONS, + TagTaskCommand.MESSAGE_USAGE)); + } + + String name = argMultimapTagTask.getValue(PREFIX_NAME).get(); + + if (name.isEmpty()) { + throw new ParseException(String.format(MESSAGE_EMPTY_NAME, TagTaskCommand.MESSAGE_USAGE)); + } + + return new TagTaskCommand(index, name); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/manageezpz/logic/parser/TagTaskPriorityCommandParser.java b/src/main/java/manageezpz/logic/parser/TagTaskPriorityCommandParser.java new file mode 100644 index 00000000000..fb18edb0b96 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/TagTaskPriorityCommandParser.java @@ -0,0 +1,85 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_PRIORITY; + +import java.util.stream.Stream; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.TagTaskPriorityCommand; +import manageezpz.logic.parser.exceptions.ParseException; +import manageezpz.model.task.Priority; + +public class TagTaskPriorityCommandParser implements Parser { + + public static final String MESSAGE_TAG_PRIORITY_TO_TASK_INSTRUCTIONS = + "Tag a priority to a task by specifying prefix priority/ " + + "followed by the priority values (NONE/LOW/MEDIUM/HIGH)!\n\n%1$s"; + + public static final String MESSAGE_EMPTY_PRIORITY = "Priority field cannot be empty! " + + "Valid priority values are NONE/LOW/MEDIUM/HIGH.\n\n%1$s"; + + public static final String MESSAGE_INVALID_PRIORITY = + "Invalid priority! " + "Valid priority values are NONE/LOW/MEDIUM/HIGH. \n\n%1$s"; + + /** + * Parses the given {@code String} of arguments in the context of the TagTaskPriorityCommand + * and returns a TagTaskPriorityCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public TagTaskPriorityCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimapTagPriority = ArgumentTokenizer.tokenize(args, PREFIX_PRIORITY); + + // Invalid command if getPreamble() is empty + if (argMultimapTagPriority.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + TagTaskPriorityCommand.MESSAGE_USAGE)); + } + + // Invalid command if getPreamble() contains whitespaces + if (argMultimapTagPriority.getPreamble().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT + " " + + MESSAGE_TAG_PRIORITY_TO_TASK_INSTRUCTIONS, TagTaskPriorityCommand.MESSAGE_USAGE)); + } + + Index index; + Priority priority; + + try { + index = ParserUtil.parseIndex(argMultimapTagPriority.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + TagTaskPriorityCommand.MESSAGE_USAGE, pe); + } + + if (!arePrefixesPresent(argMultimapTagPriority, PREFIX_PRIORITY)) { + throw new ParseException(String.format(MESSAGE_TAG_PRIORITY_TO_TASK_INSTRUCTIONS, + TagTaskPriorityCommand.MESSAGE_USAGE)); + } + + String priorityString = argMultimapTagPriority.getValue(PREFIX_PRIORITY).get(); + + if (priorityString.isEmpty()) { + throw new ParseException(String.format(MESSAGE_EMPTY_PRIORITY, + TagTaskPriorityCommand.MESSAGE_USAGE)); + } + + try { + priority = Priority.valueOf(priorityString.toUpperCase()); + } catch (IllegalArgumentException ie) { + throw new ParseException(String.format(MESSAGE_INVALID_PRIORITY, + TagTaskPriorityCommand.MESSAGE_USAGE), ie); + } + + return new TagTaskPriorityCommand(index, priority); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/manageezpz/logic/parser/UnmarkTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/UnmarkTaskCommandParser.java new file mode 100644 index 00000000000..da120375ca5 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/UnmarkTaskCommandParser.java @@ -0,0 +1,34 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.UnmarkTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new UnmarkTaskCommand object + */ +public class UnmarkTaskCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the UnmarkTaskCommand + * and returns a UnmarkTaskCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public UnmarkTaskCommand parse(String args) throws ParseException { + // Invalid command if args after trimming is empty or contains whitespaces + if (args.trim().isEmpty() || args.trim().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + UnmarkTaskCommand.MESSAGE_USAGE)); + } + + try { + Index index = ParserUtil.parseIndex(args); + return new UnmarkTaskCommand(index); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + UnmarkTaskCommand.MESSAGE_USAGE, pe); + } + } +} diff --git a/src/main/java/manageezpz/logic/parser/UntagTaskCommandParser.java b/src/main/java/manageezpz/logic/parser/UntagTaskCommandParser.java new file mode 100644 index 00000000000..7e56d72c050 --- /dev/null +++ b/src/main/java/manageezpz/logic/parser/UntagTaskCommandParser.java @@ -0,0 +1,69 @@ +package manageezpz.logic.parser; + +import static manageezpz.commons.core.Messages.MESSAGE_EMPTY_NAME; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static manageezpz.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT_BIND; +import static manageezpz.logic.parser.CliSyntax.PREFIX_NAME; + +import java.util.stream.Stream; + +import manageezpz.commons.core.index.Index; +import manageezpz.logic.commands.UntagTaskCommand; +import manageezpz.logic.parser.exceptions.ParseException; + +public class UntagTaskCommandParser implements Parser { + + public static final String MESSAGE_UNTAG_EMPLOYEE_TO_TASK_INSTRUCTIONS = + "Untag an employee from a task by specifying prefix n/ followed by the employee's full name!\n\n%1$s"; + + /** + * Parses the given {@code String} of arguments in the context of the UntagTaskCommand + * and returns an UntagTaskCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public UntagTaskCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimapUntag = ArgumentTokenizer.tokenize(args, PREFIX_NAME); + + // Invalid command if getPreamble() is empty + if (argMultimapUntag.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT_BIND, + UntagTaskCommand.MESSAGE_USAGE)); + } + + // Invalid command if getPreamble() contains whitespaces + if (argMultimapUntag.getPreamble().contains(" ")) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT + " " + + MESSAGE_UNTAG_EMPLOYEE_TO_TASK_INSTRUCTIONS, UntagTaskCommand.MESSAGE_USAGE)); + } + + Index index; + + try { + index = ParserUtil.parseIndex(argMultimapUntag.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(pe.getMessage() + "\n\n" + UntagTaskCommand.MESSAGE_USAGE, pe); + } + + if (!arePrefixesPresent(argMultimapUntag, PREFIX_NAME)) { + throw new ParseException(String.format(MESSAGE_UNTAG_EMPLOYEE_TO_TASK_INSTRUCTIONS, + UntagTaskCommand.MESSAGE_USAGE)); + } + + String name = argMultimapUntag.getValue(PREFIX_NAME).get(); + + if (name.isEmpty()) { + throw new ParseException(String.format(MESSAGE_EMPTY_NAME, UntagTaskCommand.MESSAGE_USAGE)); + } + + return new UntagTaskCommand(index, name); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/manageezpz/logic/parser/exceptions/ParseException.java similarity index 73% rename from src/main/java/seedu/address/logic/parser/exceptions/ParseException.java rename to src/main/java/manageezpz/logic/parser/exceptions/ParseException.java index 158a1a54c1c..684adeaf452 100644 --- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java +++ b/src/main/java/manageezpz/logic/parser/exceptions/ParseException.java @@ -1,6 +1,6 @@ -package seedu.address.logic.parser.exceptions; +package manageezpz.logic.parser.exceptions; -import seedu.address.commons.exceptions.IllegalValueException; +import manageezpz.commons.exceptions.IllegalValueException; /** * Represents a parse error encountered by a parser. diff --git a/src/main/java/manageezpz/model/AddressBook.java b/src/main/java/manageezpz/model/AddressBook.java new file mode 100644 index 00000000000..050139457e2 --- /dev/null +++ b/src/main/java/manageezpz/model/AddressBook.java @@ -0,0 +1,366 @@ +package manageezpz.model; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.List; + +import javafx.collections.ObservableList; +import manageezpz.model.person.Person; +import manageezpz.model.person.UniquePersonList; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Event; +import manageezpz.model.task.Priority; +import manageezpz.model.task.Task; +import manageezpz.model.task.Todo; +import manageezpz.model.task.UniqueTaskList; + +/** + * Wraps all data at the address-book level + * Duplicates are not allowed (by .isSamePerson comparison) + */ +public class AddressBook implements ReadOnlyAddressBook { + + private final UniquePersonList persons; + private final UniqueTaskList tasks; + + /* + * The 'unusual' code block below is a 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(); + tasks = new UniqueTaskList(); + } + + public AddressBook() {} + + /** + * Creates an AddressBook using the Persons in the {@code toBeCopied} + * @param toBeCopied the provided addressBook. + */ + public AddressBook(ReadOnlyAddressBook toBeCopied) { + this(); + resetData(toBeCopied); + } + + //// list overwrite operations + + /** + * Replaces the contents of the person list with {@code persons}. + * {@code persons} must not contain duplicate persons. + * @param persons the list of persons to replace the old list. + */ + public void setPersons(List persons) { + this.persons.setPersons(persons); + } + + /** + * Resets the existing data of this {@code AddressBook} with {@code newData}. + * @param newData the new addressBook to replace the old one. + */ + public void resetData(ReadOnlyAddressBook newData) { + requireNonNull(newData); + setPersons(newData.getPersonList()); + setTasks(newData.getTaskList()); + } + + /// task-level operations + + /** + * Returns true if a task with the same identity as {@code task} exists in the task list. + * @param task the task to be checked. + * @return true if same identity otherwise false. + */ + public boolean hasTask(Task task) { + requireNonNull(task); + return tasks.contains(task); + } + + /** + * Adds a Task to the task list. + * The task must not already exist in the task list. + * @param task the task to be added. + */ + public void addTask(Task task) { + tasks.add(task); + } + + /** + * Replaces the contents of the task list with {@code task}. + * {@code task} must not contain duplicate tasks. + * @param task the list of tasks to replace the old one. + */ + public void setTasks(List task) { + this.tasks.setTasks(task); + } + + /** + * Removes {@code task} from this {@code AddressBook}. + * {@code task} must exist in the address book. + * @param task the task to be removed. + */ + public void removeTask(Task task) { + tasks.remove(task); + } + + /** + * Checks if a todo with the same identity as {@code todo} exists in the task list. + * @param todo a valid Todo task. + * @return true if a todo with the same identity as {@code todo} exists in the task list, false otherwise. + */ + public boolean hasTodo(Todo todo) { + requireNonNull(todo); + return tasks.contains(todo); + } + + /** + * Adds a Todo to the task list. + * @param todo a valid Todo task. + */ + public void addTodo(Todo todo) { + this.tasks.add(todo); + } + + /** + * Check if an event with the same identity as {@code event} exists in the task list. + * @param event an event in the task list. + * @return true if event has same identity as {@code event} exists in the task list, false otherwise. + */ + public boolean hasEvent(Event event) { + requireNonNull(event); + return tasks.contains(event); + } + + /** + * Adds an Event to the task list. + * @param event a valid Event task. + */ + public void addEvent(Event event) { + this.tasks.add(event); + } + + /** + * Checks if a deadline with the same identity as {@code deadline} exists in the task list. + * @param deadline a valid deadline in the task list. + * @return true if deadline has same identity as {@code deadline} exists in the task list, false otherwise. + */ + public boolean hasDeadline(Deadline deadline) { + requireNonNull(deadline); + return tasks.contains(deadline); + } + + /** + * Adds a Deadline to the task list. + * @param deadline a valid deadline task. + */ + public void addDeadline(Deadline deadline) { + this.tasks.add(deadline); + } + + /** + * Updates the task with the edited person. + * @param task the task to be updated. + * @param assigneesIndex the index of the person in List of assignees. + * @param editedPerson the edited person. + */ + public void updateTaskWithEditedPerson(Task task, int assigneesIndex, Person editedPerson) { + requireAllNonNull(task, assigneesIndex, editedPerson); + this.tasks.updateTaskWithEditedPerson(task, assigneesIndex, editedPerson); + } + + /** + * Marks the task in the task list. + * @param task the task to be marked. + * @return the marked task. + */ + public Task markTask(Task task) { + requireNonNull(task); + return this.tasks.markTask(task); + } + + /** + * unMarks the task in the task list. + * @param task the task to be unmarked. + * @return the unmarked task. + */ + public Task unmarkTask(Task task) { + requireNonNull(task); + return this.tasks.unmarkTask(task); + } + + /** + * Tags a priority to the task. + * @param task the task to be tagged. + * @param priority the priority to be tagged to the task. + * @return the tagged task. + */ + public Task tagPriorityToTask(Task task, Priority priority) { + requireAllNonNull(task, priority); + return this.tasks.tagPriorityToTask(task, priority); + } + + /** + * Tags the task in the task list to a person in the address book. + * @param task the task to be tagged. + * @param person the person to be tagged to the task. + * @return the tagged task. + */ + public Task tagEmployeeToTask(Task task, Person person) { + requireAllNonNull(task, person); + return this.tasks.tagEmployeeToTask(task, person); + } + + /** + * Remove the Person from the Task, also decreasing the person's task count. + * @param task the task affected. + * @param person the person to be untagged from task + * @return the untagged task. + */ + public Task untagEmployeeFromTask(Task task, Person person) { + requireAllNonNull(task, person); + return this.tasks.untagEmployeeFromTask(task, person); + } + + /** + * Checks if a given Person is tagged to the task. + * @param task the task to be checked. + * @param person the person to be checked against. + * @return true if the person is tagged to the task, false otherwise. + */ + public boolean isEmployeeTaggedToTask(Task task, Person person) { + requireAllNonNull(task, person); + return task.getAssignees().contains(person); + } + + /** + * Checks if a given task has a priority tagged to it. + * @param task the task to be checked. + * @return true if the task is tagged with a priority, false otherwise. + */ + public boolean hasPriority(Task task) { + requireNonNull(task); + boolean returnValue; + if (task.getPriority() != null) { + returnValue = true; + } else { + returnValue = false; + } + return returnValue; + } + + /** + * Replaces the given task {@code target} in the list with {@code editedTask}. + * {@code target} must exist in the task list. + * The task identity of {@code editedTask} must not be the same as another existing task in the task list. + * @param target the task to be replaced. + * @param editedTask the new task to replace the target. + */ + public void setTask(Task target, Task editedTask) { + requireNonNull(editedTask); + tasks.setTask(target, editedTask); + } + + //// person-level operations + + /** + * Checks if a person with the same identity as {@code person} exists in the address book. + * @param person the person to be checked. + * @return true if a person has the same identity as the person specified, false otherwise. + */ + public boolean hasPerson(Person person) { + requireNonNull(person); + return persons.contains(person); + } + + /** + * Adds a person to the address book. + * The person must not already exist in the address book. + * @param person the person to be added. + */ + public void addPerson(Person person) { + persons.add(person); + } + + /** + * Replaces the given person {@code target} in the list with {@code editedPerson}. + * {@code target} must exist in the address book. + * The person identity of {@code editedPerson} must not be the same as another existing person in the address book. + * @param target the person to be replaced. + * @param editedPerson the new person to replace the target. + */ + public void setPerson(Person target, Person editedPerson) { + requireNonNull(editedPerson); + persons.setPerson(target, editedPerson); + } + + /** + * Increments the number of task associated with the person. + * @param person the person whose number of task is to be incremented. + */ + public void increaseNumOfTasks(Person person) { + requireNonNull(person); + this.persons.increaseNumOfTasks(person); + } + + /** + * Decrements the number of task associated with the person. + * @param person the person whose number of task is to be decremented. + */ + public void decreaseNumOfTasks(Person person) { + requireNonNull(person); + this.persons.decreaseNumOfTasks(person); + } + + /** + * Removes {@code key} from this {@code AddressBook}. + * {@code key} must exist in the address book. + * @param key the person to be removed. + */ + public void removePerson(Person key) { + persons.remove(key); + } + + //// util methods + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return persons.asUnmodifiableObservableList().size() + " persons"; + // TODO: refine later + } + + @Override + public ObservableList getPersonList() { + return persons.asUnmodifiableObservableList(); + } + + @Override + public ObservableList getTaskList() { + return tasks.asUnmodifiableObservableList(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddressBook // instanceof handles nulls + && persons.equals(((AddressBook) other).persons) + && tasks.equals(((AddressBook) other).tasks)); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return persons.hashCode(); + } +} diff --git a/src/main/java/manageezpz/model/Model.java b/src/main/java/manageezpz/model/Model.java new file mode 100644 index 00000000000..79717d16457 --- /dev/null +++ b/src/main/java/manageezpz/model/Model.java @@ -0,0 +1,283 @@ +package manageezpz.model; + +import java.nio.file.Path; +import java.util.function.Predicate; + +import javafx.collections.ObservableList; +import manageezpz.commons.core.GuiSettings; +import manageezpz.model.person.Person; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Event; +import manageezpz.model.task.Priority; +import manageezpz.model.task.Task; +import manageezpz.model.task.Todo; + +/** + * The API of the Model component. + */ +public interface Model { + /** {@code Predicate} that always evaluate to true to show all tasks */ + Predicate PREDICATE_SHOW_ALL_TASKS = unused -> true; + /** {@code Predicate} that always evaluate to true */ + Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true; + + /** + * Replaces user prefs data with the data in {@code userPrefs}. + * @param userPrefs the userPrefs to be replaced with. + */ + void setUserPrefs(ReadOnlyUserPrefs userPrefs); + + /** + * Gets the user preference. + * @return the user preference. + */ + ReadOnlyUserPrefs getUserPrefs(); + + /** + * Gets the user prefs' GUI settings. + * @return the user prefs' GUI settings. + */ + GuiSettings getGuiSettings(); + + /** + * Sets the user prefs' GUI settings. + * @param guiSettings the guiSettings to be set. + */ + void setGuiSettings(GuiSettings guiSettings); + + /** + * Gets the user prefs' address book file path. + * @return the user prefs' address book file path. + */ + Path getAddressBookFilePath(); + + /** + * Sets the user prefs' address book file path. + * @param addressBookFilePath the provided file path. + */ + void setAddressBookFilePath(Path addressBookFilePath); + + /** + * Replaces address book data with the data in {@code addressBook}. + * @param addressBook the addressBook to be replaced with. + */ + void setAddressBook(ReadOnlyAddressBook addressBook); + + /** + * Gets the AddressBook + * @return the AddressBook. + */ + ReadOnlyAddressBook getAddressBook(); + + /** + * Checks if a person with the same identity as {@code person} exists in the address book. + * @param person the person to be checked against. + * @return true if a person has the same identity, false otherwise. + */ + boolean hasPerson(Person person); + + /** + * Deletes the given person. + * The person must exist in the address book. + * @param target the person to be deleted. + */ + void deletePerson(Person target); + + /** + * Adds the given person. + * {@code person} must not already exist in the address book. + * @param person the person to be added. + */ + void addPerson(Person person); + + /** + * Replaces the given person {@code target} with {@code editedPerson}. + * {@code target} must exist in the address book. + * The person identity of {@code editedPerson} must not be the same as another existing person in the address book. + * @param target the person to be replaced. + * @param editedPerson the new person to replace the target. + */ + void setPerson(Person target, Person editedPerson); + + /** + * Increments the number of task associated with the person. + * @param person the person whose number of task is to be incremented. + */ + void increaseNumOfTasks(Person person); + + /** + * Decrements the number of task associated with the person. + * @param person the person whose number of task is to be decremented. + */ + void decreaseNumOfTasks(Person person); + + /** + * Gets an unmodifiable view of the filtered person list + * @return an unmodifiable view of the filtered person list + */ + ObservableList getFilteredPersonList(); + + /** + * Updates the filter of the filtered person list to filter by the given {@code predicate}. + * @param predicate the provided condition. + * @throws NullPointerException if {@code predicate} is null. + */ + void updateFilteredPersonList(Predicate predicate); + + + //=========== ManageEZPZ (Tasks) ================================================================================== + + /** + * Deletes the given task. + * The task must exist in the task list. + * @param task the task to be deleted. + */ + void deleteTask(Task task); + + /** + * Updates the task with the edited person. + * The task must exist in the task list. + * @param task the task to be updated. + * @param assigneesIndex the index to the Persons List. + * @param editedPerson the person to update with. + */ + void updateTaskWithEditedPerson(Task task, int assigneesIndex, Person editedPerson); + + /** + * Marks the given task. + * The task must exist in the task list. + * @param task the task to be marked. + * @return the marked task. + */ + Task markTask(Task task); + + /** + * unMarks the given task. + * The task must exist in the task list. + * @param task the task to be unmarked. + * @return the unmarked task. + */ + Task unmarkTask(Task task); + + /** + * Assigns a task to a priority. + * @param task the task to be assigned. + * @param priority the priority to be assigned to the task. + * @return the assigned task with the provided priority. + */ + Task tagPriorityToTask(Task task, Priority priority); + + + /** + * Tags the given task to the specified person. + * The task must exist in the task list. + * The person must exist in the address book. + * @param task the task to be tagged. + * @param person the person to be tagged to by the task. + * @return the tagged task. + */ + Task tagEmployeeToTask(Task task, Person person); + + + /** + * Untags the given task from the specified person. + * The task must exist in the task list. + * The person must exist in the address book. + * @param task the task to be untagged. + * @param person the person to be untagged from by the task. + * @return the untagged task. + */ + Task untagEmployeeFromTask(Task task, Person person); + + /** + * Adds the given task. + * {@code task} must not already exist in the task list + * @param task the task to be added. + */ + void addTask(Task task); + + /** + * Adds the given todo Task. + * {@code Todo} must not already exist in the task list + * @param todo the todo Task to be added. + */ + void addTodo(Todo todo); + + /** + * Adds the given event. + * {@code event} must not already exist in the task list + * @param event the event Task to be added. + */ + void addEvent(Event event); + + /** + * Adds the given deadline. + * {@code deadline} must not already exist in the task list + * @param deadline the deadline Task to be added. + */ + void addDeadline(Deadline deadline); + + /** + * Updates the filter of the filtered task list to filter by the given {@code predicate}. + * @param predicate the given condition. + * @throws NullPointerException if {@code predicate} is null. + */ + void updateFilteredTaskList(Predicate predicate); + + /** + * Gets an unmodifiable view of the filtered task list. + * @return an unmodifiable view of the filtered task list. + */ + ObservableList getFilteredTaskList(); + + /** + * Checks if the Task list has the specified task. + * @param task the task to be checked. + * @return true if a task with the same identity as {@code Task} exists in the task list, false otherwise. + */ + boolean hasTask(Task task); + + /** + * Checks if the Task list has the specified todo task. + * @param todo the task to be checked. + * @return true if a task with the same identity as {@code Todo} exists in the task list, false otherwise. + */ + boolean hasTodo(Todo todo); + + /** + * Checks if the Task list has the specified deadline task. + * @param deadline the task to be checked. + * @return true if a task with the same identity as {@code Deadline} exists in the task list, false otherwise. + */ + boolean hasDeadline(Deadline deadline); + + /** + * Checks if the Task list has the specified event task. + * @param event the task to be checked. + * @return true if a task with the same identity as {@code Event} exists in the task list, false otherwise. + */ + boolean hasEvent(Event event); + + /** + * Checks if a Person is tagged to the specified task. + * @param task the task to be checked. + * @param person the person to be checked. + * @return true if a {@code Task} is tagged to the person {@code Person}, false otherwise. + */ + boolean isEmployeeTaggedToTask(Task task, Person person); + + + /** + * Returns true if a {@code Task} is allocated with a priority. + */ + boolean hasPriority(Task task); + + /** + * Replaces the given task {@code target} with {@code editedTask}. + * {@code target} must exist in the task list. + * The task identity of {@code editedTask} must not be the same as another existing task in the task list. + * @param target the task to be replaced. + * @param editedTask the new task to replace the target. + */ + void setTask(Task target, Task editedTask); +} diff --git a/src/main/java/manageezpz/model/ModelManager.java b/src/main/java/manageezpz/model/ModelManager.java new file mode 100644 index 00000000000..bbda070e1f1 --- /dev/null +++ b/src/main/java/manageezpz/model/ModelManager.java @@ -0,0 +1,303 @@ +package manageezpz.model; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; + +import java.nio.file.Path; +import java.util.function.Predicate; +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; +import manageezpz.commons.core.GuiSettings; +import manageezpz.commons.core.LogsCenter; +import manageezpz.model.person.Person; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Event; +import manageezpz.model.task.Priority; +import manageezpz.model.task.Task; +import manageezpz.model.task.Todo; + +/** + * Represents the in-memory model of the address book data. + */ +public class ModelManager implements Model { + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private final AddressBook addressBook; + private final UserPrefs userPrefs; + private final FilteredList filteredPersons; + private final FilteredList filteredTasks; + + /** + * Initializes a ModelManager with the given addressBook and userPrefs. + * @param addressBook the provided addressBook. + * @param userPrefs the specified user preferences. + */ + public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) { + requireAllNonNull(addressBook, userPrefs); + + logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs); + + this.addressBook = new AddressBook(addressBook); + this.userPrefs = new UserPrefs(userPrefs); + + filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); + filteredTasks = new FilteredList<>(this.addressBook.getTaskList()); + } + + /** + * Initializes a ModelManager with an empty addressBook and default user preferences. + */ + public ModelManager() { + this(new AddressBook(), new UserPrefs()); + } + + //=========== UserPrefs ================================================================================== + @Override + public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { + requireNonNull(userPrefs); + this.userPrefs.resetData(userPrefs); + } + + @Override + public ReadOnlyUserPrefs getUserPrefs() { + return userPrefs; + } + + @Override + public GuiSettings getGuiSettings() { + return userPrefs.getGuiSettings(); + } + + @Override + public void setGuiSettings(GuiSettings guiSettings) { + requireNonNull(guiSettings); + userPrefs.setGuiSettings(guiSettings); + } + + @Override + public Path getAddressBookFilePath() { + return userPrefs.getAddressBookFilePath(); + } + + @Override + public void setAddressBookFilePath(Path addressBookFilePath) { + requireNonNull(addressBookFilePath); + userPrefs.setAddressBookFilePath(addressBookFilePath); + } + + //=========== AddressBook ================================================================================ + + @Override + public void setAddressBook(ReadOnlyAddressBook addressBook) { + this.addressBook.resetData(addressBook); + } + + @Override + public ReadOnlyAddressBook getAddressBook() { + return addressBook; + } + + @Override + public boolean hasPerson(Person person) { + requireNonNull(person); + return addressBook.hasPerson(person); + } + + @Override + public void deletePerson(Person target) { + addressBook.removePerson(target); + } + + @Override + public void addPerson(Person person) { + requireNonNull(person); + addressBook.addPerson(person); + updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + } + + @Override + public void setPerson(Person target, Person editedPerson) { + requireAllNonNull(target, editedPerson); + addressBook.setPerson(target, editedPerson); + } + + @Override + public void increaseNumOfTasks(Person person) { + requireNonNull(person); + addressBook.increaseNumOfTasks(person); + } + + @Override + public void decreaseNumOfTasks(Person person) { + requireNonNull(person); + addressBook.decreaseNumOfTasks(person); + } + + //=========== Filtered Person List Accessors ============================================================= + + /** + * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of + * {@code versionedAddressBook} + */ + @Override + public ObservableList getFilteredPersonList() { + return filteredPersons; + } + + @Override + public void updateFilteredPersonList(Predicate predicate) { + requireNonNull(predicate); + filteredPersons.setPredicate(predicate); + } + + //=========== ManageEZPZ ================================================================================== + + @Override + public boolean hasTask(Task task) { + requireNonNull(task); + return addressBook.hasTask(task); + } + + @Override + public void addTask(Task task) { + requireNonNull(task); + addressBook.addTask(task); + updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + } + + @Override + public void addTodo(Todo todo) { + addressBook.addTodo(todo); + updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + } + + @Override + public void addEvent(Event event) { + addressBook.addEvent(event); + updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + } + + @Override + public void addDeadline(Deadline deadline) { + addressBook.addDeadline(deadline); + updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + } + + @Override + public boolean hasDeadline(Deadline deadline) { + requireNonNull(deadline); + return addressBook.hasDeadline(deadline); + } + + @Override + public boolean hasEvent(Event event) { + requireNonNull(event); + return addressBook.hasEvent(event); + } + + @Override + public boolean hasTodo(Todo todo) { + requireNonNull(todo); + return addressBook.hasTodo(todo); + } + + @Override + public void deleteTask(Task task) { + requireNonNull(task); + addressBook.removeTask(task); + } + + @Override + public void updateTaskWithEditedPerson(Task task, int assigneesIndex, Person editedPerson) { + requireAllNonNull(task, assigneesIndex, editedPerson); + addressBook.updateTaskWithEditedPerson(task, assigneesIndex, editedPerson); + } + + @Override + public Task markTask(Task task) { + requireNonNull(task); + return addressBook.markTask(task); + } + + @Override + public Task unmarkTask(Task task) { + requireNonNull(task); + return addressBook.unmarkTask(task); + } + + @Override + public Task tagPriorityToTask(Task task, Priority priority) { + requireAllNonNull(task, priority); + return addressBook.tagPriorityToTask(task, priority); + } + + @Override + public Task tagEmployeeToTask(Task task, Person person) { + requireAllNonNull(task, person); + return addressBook.tagEmployeeToTask(task, person); + } + + @Override + public Task untagEmployeeFromTask(Task task, Person person) { + requireAllNonNull(task, person); + return addressBook.untagEmployeeFromTask(task, person); + } + + @Override + public boolean isEmployeeTaggedToTask(Task task, Person person) { + requireAllNonNull(task, person); + return addressBook.isEmployeeTaggedToTask(task, person); + } + + //=========== Filtered Task List Accessors ============================================================= + + /** + * Returns an unmodifiable view of the list of {@code Task} backed by the internal list of + * {@code versionedAddressBook} + */ + @Override + public ObservableList getFilteredTaskList() { + return filteredTasks; + } + + @Override + public void updateFilteredTaskList(Predicate predicate) { + requireNonNull(predicate); + filteredTasks.setPredicate(predicate); + } + + + @Override + public boolean equals(Object obj) { + // short circuit if same object + if (obj == this) { + return true; + } + + // instanceof handles nulls + if (!(obj instanceof ModelManager)) { + return false; + } + + // state check + ModelManager other = (ModelManager) obj; + return addressBook.equals(other.addressBook) + && userPrefs.equals(other.userPrefs) + && filteredPersons.equals(other.filteredPersons) + && filteredTasks.equals(other.filteredTasks); + } + + @Override + public boolean hasPriority(Task task) { + return addressBook.hasPriority(task); + } + + @Override + public void setTask(Task target, Task editedTask) { + requireAllNonNull(target, editedTask); + addressBook.setTask(target, editedTask); + } + +} diff --git a/src/main/java/manageezpz/model/ReadOnlyAddressBook.java b/src/main/java/manageezpz/model/ReadOnlyAddressBook.java new file mode 100644 index 00000000000..8c19ce1107a --- /dev/null +++ b/src/main/java/manageezpz/model/ReadOnlyAddressBook.java @@ -0,0 +1,26 @@ +package manageezpz.model; + +import javafx.collections.ObservableList; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; + +/** + * 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. + * @return the persons list. + */ + ObservableList getPersonList(); + + /** + * Returns an unmodifiable view of the task list. + * This list will not contain any duplicate task. + * @return the task list. + */ + ObservableList getTaskList(); + +} diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/manageezpz/model/ReadOnlyUserPrefs.java similarity index 70% rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java rename to src/main/java/manageezpz/model/ReadOnlyUserPrefs.java index befd58a4c73..23f84ffa67c 100644 --- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java +++ b/src/main/java/manageezpz/model/ReadOnlyUserPrefs.java @@ -1,8 +1,8 @@ -package seedu.address.model; +package manageezpz.model; import java.nio.file.Path; -import seedu.address.commons.core.GuiSettings; +import manageezpz.commons.core.GuiSettings; /** * Unmodifiable view of user prefs. diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/manageezpz/model/UserPrefs.java similarity index 85% rename from src/main/java/seedu/address/model/UserPrefs.java rename to src/main/java/manageezpz/model/UserPrefs.java index 25a5fd6eab9..5cb3f2d16c4 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/manageezpz/model/UserPrefs.java @@ -1,4 +1,4 @@ -package seedu.address.model; +package manageezpz.model; import static java.util.Objects.requireNonNull; @@ -6,7 +6,7 @@ import java.nio.file.Paths; import java.util.Objects; -import seedu.address.commons.core.GuiSettings; +import manageezpz.commons.core.GuiSettings; /** * Represents User's preferences. @@ -14,7 +14,7 @@ public class UserPrefs implements ReadOnlyUserPrefs { private GuiSettings guiSettings = new GuiSettings(); - private Path addressBookFilePath = Paths.get("data" , "addressbook.json"); + private Path addressBookFilePath = Paths.get("data" , "ManageEZPZ.json"); /** * Creates a {@code UserPrefs} with default values. @@ -23,6 +23,7 @@ public UserPrefs() {} /** * Creates a {@code UserPrefs} with the prefs in {@code userPrefs}. + * @param userPrefs the provided user preferences. */ public UserPrefs(ReadOnlyUserPrefs userPrefs) { this(); @@ -31,6 +32,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) { /** * Resets the existing data of this {@code UserPrefs} with {@code newUserPrefs}. + * @param newUserPrefs the new user preferences. */ public void resetData(ReadOnlyUserPrefs newUserPrefs) { requireNonNull(newUserPrefs); @@ -56,6 +58,9 @@ public void setAddressBookFilePath(Path addressBookFilePath) { this.addressBookFilePath = addressBookFilePath; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { if (other == this) { @@ -71,11 +76,17 @@ public boolean equals(Object other) { && addressBookFilePath.equals(o.addressBookFilePath); } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return Objects.hash(guiSettings, addressBookFilePath); } + /** + * {@inheritDoc} + */ @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/manageezpz/model/person/Email.java similarity index 88% rename from src/main/java/seedu/address/model/person/Email.java rename to src/main/java/manageezpz/model/person/Email.java index f866e7133de..4572625f70a 100644 --- a/src/main/java/seedu/address/model/person/Email.java +++ b/src/main/java/manageezpz/model/person/Email.java @@ -1,7 +1,7 @@ -package seedu.address.model.person; +package manageezpz.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static manageezpz.commons.util.AppUtil.checkArgument; /** * Represents a Person's email in the address book. @@ -45,17 +45,25 @@ public Email(String email) { } /** - * Returns if a given string is a valid email. + * Checks if a given string is a valid email. + * @param test the email to be checked. + * @return true if the given email is valid, false otherwise. */ public static boolean isValidEmail(String test) { return test.matches(VALIDATION_REGEX); } + /** + * {@inheritDoc} + */ @Override public String toString() { return value; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -63,6 +71,9 @@ public boolean equals(Object other) { && value.equals(((Email) other).value)); // state check } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return value.hashCode(); diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/manageezpz/model/person/Name.java similarity index 71% rename from src/main/java/seedu/address/model/person/Name.java rename to src/main/java/manageezpz/model/person/Name.java index 79244d71cf7..fd065de34c5 100644 --- a/src/main/java/seedu/address/model/person/Name.java +++ b/src/main/java/manageezpz/model/person/Name.java @@ -1,7 +1,7 @@ -package seedu.address.model.person; +package manageezpz.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static manageezpz.commons.util.AppUtil.checkArgument; /** * Represents a Person's name in the address book. @@ -10,13 +10,7 @@ public class Name { public static final String MESSAGE_CONSTRAINTS = - "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 VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + "Names should only contain alphanumeric characters and spaces, and it should not be blank."; public final String fullName; @@ -32,18 +26,26 @@ public Name(String name) { } /** - * Returns true if a given string is a valid name. + * Checks if a given string is a valid name. + * @param test the name to be checked. + * @return true if the name is valid, false otherwise. */ public static boolean isValidName(String test) { - return test.matches(VALIDATION_REGEX); + return !test.trim().isEmpty(); } + /** + * {@inheritDoc} + */ @Override public String toString() { return fullName; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -51,6 +53,9 @@ public boolean equals(Object other) { && fullName.equals(((Name) other).fullName)); // state check } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return fullName.hashCode(); diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/manageezpz/model/person/Person.java similarity index 53% rename from src/main/java/seedu/address/model/person/Person.java rename to src/main/java/manageezpz/model/person/Person.java index 8ff1d83fe89..888a317c709 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/manageezpz/model/person/Person.java @@ -1,13 +1,9 @@ -package seedu.address.model.person; +package manageezpz.model.person; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; -import java.util.Collections; -import java.util.HashSet; import java.util.Objects; -import java.util.Set; -import seedu.address.model.tag.Tag; /** * Represents a Person in the address book. @@ -19,21 +15,21 @@ public class Person { private final Name name; private final Phone phone; private final Email email; - - // Data fields - private final Address address; - private final Set tags = new HashSet<>(); + private int numOfTasks; /** - * Every field must be present and not null. + * Constructs an {@code Person}. + * @param name A valid name. + * @param phone A valid phone number. + * @param email A valid Email. + * @param numOfTasks the number of task assigned to the person. */ - public Person(Name name, Phone phone, Email email, Address address, Set tags) { - requireAllNonNull(name, phone, email, address, tags); + public Person(Name name, Phone phone, Email email, int numOfTasks) { + requireAllNonNull(name, phone, email); this.name = name; this.phone = phone; this.email = email; - this.address = address; - this.tags.addAll(tags); + this.numOfTasks = numOfTasks; } public Name getName() { @@ -48,21 +44,15 @@ public Email getEmail() { return email; } - public Address getAddress() { - return address; - } - - /** - * Returns an immutable tag set, which throws {@code UnsupportedOperationException} - * if modification is attempted. - */ - public Set getTags() { - return Collections.unmodifiableSet(tags); + public int getNumOfTasks() { + return numOfTasks; } /** - * Returns true if both persons have the same name. + * Returns true if both persons have the same name or email or phone number. * This defines a weaker notion of equality between two persons. + * @param otherPerson the person to check against. + * @return true if both persons are the same, false otherwise. */ public boolean isSamePerson(Person otherPerson) { if (otherPerson == this) { @@ -70,7 +60,25 @@ public boolean isSamePerson(Person otherPerson) { } return otherPerson != null - && otherPerson.getName().equals(getName()); + && (otherPerson.getName().equals(getName()) + || otherPerson.getEmail().equals(getEmail()) + || otherPerson.getPhone().equals(getPhone())); + } + + /** + * Increases the number of tasks by one. + */ + public void increaseTaskCount() { + this.numOfTasks = numOfTasks + 1; + } + + /** + * Decreases the number of tasks by one. + * At any time, the number of tasks should not be lesser than zero. + */ + public void decreaseTaskCount() { + assert numOfTasks >= 0 : "numOfTasks should not be lesser than 0"; + this.numOfTasks = numOfTasks - 1; } /** @@ -90,17 +98,21 @@ public boolean equals(Object other) { Person otherPerson = (Person) other; return otherPerson.getName().equals(getName()) && otherPerson.getPhone().equals(getPhone()) - && otherPerson.getEmail().equals(getEmail()) - && otherPerson.getAddress().equals(getAddress()) - && otherPerson.getTags().equals(getTags()); + && otherPerson.getEmail().equals(getEmail()); } + /** + * {@inheritDoc} + */ @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); + return Objects.hash(name, phone, email); } + /** + * {@inheritDoc} + */ @Override public String toString() { final StringBuilder builder = new StringBuilder(); @@ -108,15 +120,7 @@ public String toString() { .append("; Phone: ") .append(getPhone()) .append("; Email: ") - .append(getEmail()) - .append("; Address: ") - .append(getAddress()); - - Set tags = getTags(); - if (!tags.isEmpty()) { - builder.append("; Tags: "); - tags.forEach(builder::append); - } + .append(getEmail()); return builder.toString(); } diff --git a/src/main/java/manageezpz/model/person/PersonMultiplePredicate.java b/src/main/java/manageezpz/model/person/PersonMultiplePredicate.java new file mode 100644 index 00000000000..1c059fa0206 --- /dev/null +++ b/src/main/java/manageezpz/model/person/PersonMultiplePredicate.java @@ -0,0 +1,85 @@ +package manageezpz.model.person; + +import java.util.List; +import java.util.function.Predicate; + +import manageezpz.commons.util.StringUtil; + +/** + * Checks if the options are valid for finding tasks. + */ +public class PersonMultiplePredicate implements Predicate { + private final List names; + private final String phone; + private final String email; + + /** + * The constructor for the multipredicate to search for employees with the stated options. + * @param names Name of the employee + * @param phone Phone number of the employee + * @param email Email of the employee. + */ + public PersonMultiplePredicate(List names, String phone, String email) { + this.names = names; + this.phone = phone; + this.email = email; + + boolean isAtLeastOneNotNull = (this.names != null) || (this.phone != null) || (this.email != null); + assert isAtLeastOneNotNull : "At least one search option should be specified"; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean test(Person person) { + // Checks if the specific search term is specified in the parameter, then check on the person provided. + // Defaults to true if not specified. + boolean hasName = names != null ? checkIfNameExists(person) : true; + boolean hasPhone = phone != null ? checkIfPhoneExists(person) : true; + boolean hasEmail = email != null ? checkIfEmailExists(person) : true; + + return hasName && hasPhone && hasEmail; + } + + private boolean checkIfNameExists(Person person) { + return names.stream().anyMatch(name -> StringUtil.containsWordIgnoreCase(person.getName().fullName, name)); + } + + private boolean checkIfPhoneExists(Person person) { + Phone phone = new Phone(this.phone); + return person.getPhone().equals(phone); + } + + private boolean checkIfEmailExists(Person person) { + Email email = new Email(this.email); + return person.getEmail().equals(email); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } else if (other instanceof PersonMultiplePredicate) { + PersonMultiplePredicate otherPredicate = (PersonMultiplePredicate) other; + boolean isNameEquals = checkIfOptionEqual(names, otherPredicate.names); + boolean isPhoneEquals = checkIfOptionEqual(phone, otherPredicate.phone); + boolean isEmailEquals = checkIfOptionEqual(email, otherPredicate.email); + + return isNameEquals && isPhoneEquals && isEmailEquals; + } else { + return false; + } + } + + private boolean checkIfOptionEqual(Object currentObj, Object otherObj) { + if (otherObj != null) { + return otherObj.equals(currentObj); + } else { + return currentObj == null; + } + } +} diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/manageezpz/model/person/Phone.java similarity index 74% rename from src/main/java/seedu/address/model/person/Phone.java rename to src/main/java/manageezpz/model/person/Phone.java index 872c76b382f..82f7116e7b7 100644 --- a/src/main/java/seedu/address/model/person/Phone.java +++ b/src/main/java/manageezpz/model/person/Phone.java @@ -1,7 +1,7 @@ -package seedu.address.model.person; +package manageezpz.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static manageezpz.commons.util.AppUtil.checkArgument; /** * Represents a Person's phone number in the address book. @@ -9,9 +9,9 @@ */ public class Phone { - public static final String MESSAGE_CONSTRAINTS = - "Phone numbers should only contain numbers, and it should be at least 3 digits long"; + "Phone numbers should only contain numbers, and it should be at least 3 digits long."; + public static final String VALIDATION_REGEX = "\\d{3,}"; public final String value; @@ -27,17 +27,25 @@ public Phone(String phone) { } /** - * Returns true if a given string is a valid phone number. + * Checks if a given string is a valid phone number. + * @param test the phone number to be checked. + * @return true if the phone number is valid, false otherwise. */ public static boolean isValidPhone(String test) { return test.matches(VALIDATION_REGEX); } + /** + * {@inheritDoc} + */ @Override public String toString() { return value; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -45,6 +53,9 @@ public boolean equals(Object other) { && value.equals(((Phone) other).value)); // state check } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return value.hashCode(); diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/manageezpz/model/person/UniquePersonList.java similarity index 64% rename from src/main/java/seedu/address/model/person/UniquePersonList.java rename to src/main/java/manageezpz/model/person/UniquePersonList.java index 0fee4fe57e6..04cf849a089 100644 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ b/src/main/java/manageezpz/model/person/UniquePersonList.java @@ -1,22 +1,22 @@ -package seedu.address.model.person; +package manageezpz.model.person; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; import java.util.Iterator; import java.util.List; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import seedu.address.model.person.exceptions.DuplicatePersonException; -import seedu.address.model.person.exceptions.PersonNotFoundException; +import manageezpz.model.person.exceptions.DuplicatePersonException; +import manageezpz.model.person.exceptions.PersonNotFoundException; /** * A list of persons that enforces uniqueness between its elements and does not allow nulls. * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of - * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is - * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so - * as to ensure that the person with exactly the same fields will be removed. + * persons uses Person#isSamePerson(Person) for equality to ensure that the person being added or updated is + * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) + * to ensure that the person with exactly the same fields will be removed. * * Supports a minimal set of list operations. * @@ -29,7 +29,9 @@ public class UniquePersonList implements Iterable { FXCollections.unmodifiableObservableList(internalList); /** - * Returns true if the list contains an equivalent person as the given argument. + * Checks if the list contains an equivalent person as the given argument. + * @param toCheck the person to be checked. + * @return true if the list contains the specified person, false otherwise. */ public boolean contains(Person toCheck) { requireNonNull(toCheck); @@ -39,6 +41,7 @@ public boolean contains(Person toCheck) { /** * Adds a person to the list. * The person must not already exist in the list. + * @param toAdd the person to be added. */ public void add(Person toAdd) { requireNonNull(toAdd); @@ -52,6 +55,8 @@ public void add(Person toAdd) { * Replaces the person {@code target} in the list with {@code editedPerson}. * {@code target} must exist in the list. * The person identity of {@code editedPerson} must not be the same as another existing person in the list. + * @param target the person to be replaced. + * @param editedPerson the new person to replace the target. */ public void setPerson(Person target, Person editedPerson) { requireAllNonNull(target, editedPerson); @@ -68,9 +73,38 @@ public void setPerson(Person target, Person editedPerson) { internalList.set(index, editedPerson); } + /** + * Increases the number of tasks by one. + * @param person the person to increment the number of tasks. + */ + public void increaseNumOfTasks(Person person) { + requireNonNull(person); + + Person updatedPerson = new Person(person.getName(), person.getPhone(), + person.getEmail(), person.getNumOfTasks()); + updatedPerson.increaseTaskCount(); + + setPerson(person, updatedPerson); + } + + /** + * Decreases the number of tasks by one. + * @param person the person to decrement the number of tasks. + */ + public void decreaseNumOfTasks(Person person) { + requireNonNull(person); + + Person updatedPerson = new Person(person.getName(), person.getPhone(), + person.getEmail(), person.getNumOfTasks()); + updatedPerson.decreaseTaskCount(); + + setPerson(person, updatedPerson); + } + /** * Removes the equivalent person from the list. * The person must exist in the list. + * @param toRemove the person to be removed. */ public void remove(Person toRemove) { requireNonNull(toRemove); @@ -79,6 +113,10 @@ public void remove(Person toRemove) { } } + /** + * Replaces the current person list with the provided list. + * @param replacement the list to replace the current person list. + */ public void setPersons(UniquePersonList replacement) { requireNonNull(replacement); internalList.setAll(replacement.internalList); @@ -87,6 +125,7 @@ public void setPersons(UniquePersonList replacement) { /** * Replaces the contents of this list with {@code persons}. * {@code persons} must not contain duplicate persons. + * @param persons the list to replace the old list. */ public void setPersons(List persons) { requireAllNonNull(persons); @@ -99,16 +138,23 @@ public void setPersons(List persons) { /** * Returns the backing list as an unmodifiable {@code ObservableList}. + * @return the unmodifiable persons list. */ public ObservableList asUnmodifiableObservableList() { return internalUnmodifiableList; } + /** + * {@inheritDoc} + */ @Override public Iterator iterator() { return internalList.iterator(); } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -116,14 +162,14 @@ public boolean equals(Object other) { && internalList.equals(((UniquePersonList) other).internalList)); } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return internalList.hashCode(); } - /** - * Returns true if {@code persons} contains only unique persons. - */ private boolean personsAreUnique(List persons) { for (int i = 0; i < persons.size() - 1; i++) { for (int j = i + 1; j < persons.size(); j++) { diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/manageezpz/model/person/exceptions/DuplicatePersonException.java similarity index 87% rename from src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java rename to src/main/java/manageezpz/model/person/exceptions/DuplicatePersonException.java index d7290f59442..20761c1f143 100644 --- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java +++ b/src/main/java/manageezpz/model/person/exceptions/DuplicatePersonException.java @@ -1,4 +1,4 @@ -package seedu.address.model.person.exceptions; +package manageezpz.model.person.exceptions; /** * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/manageezpz/model/person/exceptions/PersonNotFoundException.java similarity index 75% rename from src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java rename to src/main/java/manageezpz/model/person/exceptions/PersonNotFoundException.java index fa764426ca7..7b7463345aa 100644 --- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java +++ b/src/main/java/manageezpz/model/person/exceptions/PersonNotFoundException.java @@ -1,4 +1,4 @@ -package seedu.address.model.person.exceptions; +package manageezpz.model.person.exceptions; /** * Signals that the operation is unable to find the specified person. diff --git a/src/main/java/manageezpz/model/task/Date.java b/src/main/java/manageezpz/model/task/Date.java new file mode 100644 index 00000000000..cd47393c22b --- /dev/null +++ b/src/main/java/manageezpz/model/task/Date.java @@ -0,0 +1,91 @@ +package manageezpz.model.task; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.util.AppUtil.checkArgument; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + + +public class Date { + public static final String MESSAGE_CONSTRAINTS = "Date should be in the format of yyyy-MM-dd.\n" + + "Year should be greater then 0000, Month should only be between 1 and 12 " + + "and Day should only be between 1 and 31."; + + public static final String VALIDATION_REGEX = "(?!0000)\\d{4}\\D\\d{2}\\D\\d{2}"; + + private String date; + + /** + * Constructs a {@code Date}. + * @param date A valid date. + */ + public Date(String date) { + requireNonNull(date); + checkArgument(isValidDate(date), MESSAGE_CONSTRAINTS); + this.date = date; + } + + public String getDate() { + return date; + } + + public LocalDate getParsedDate() { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate parsedDate = LocalDate.parse(date, dtf); + return parsedDate; + } + + public static Date getTodayDate() { + LocalDate todayDate = LocalDate.now(); + return new Date(todayDate.toString()); + } + + /** + * Checks if the given date is valid. + * @param date the date to be checked. + * @return true if the date is valid, false otherwise. + */ + public static boolean isValidDate(String date) { + return date.matches(VALIDATION_REGEX) && validCheckDate(date); + } + + /** + * Validates the format of date provided. + * @param date String representation of date. + * @return true if date is in the correct parsable format, false otherwise. + * */ + public static boolean validCheckDate(String date) { + SimpleDateFormat sdfrmt = new SimpleDateFormat("yyyy-MM-dd"); + sdfrmt.setLenient(false); + try { + LocalDate.parse(date); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + + /** + * Formats the given date. + * @param dtf the DateTimeFormatter to be used to format the date. + * @return the formatted date. + */ + public String format(DateTimeFormatter dtf) { + return getParsedDate().format(dtf); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof Date) { + return date.equals(((Date) obj).date); + } else { + return false; + } + } +} diff --git a/src/main/java/manageezpz/model/task/Deadline.java b/src/main/java/manageezpz/model/task/Deadline.java new file mode 100644 index 00000000000..12cbefc1a2f --- /dev/null +++ b/src/main/java/manageezpz/model/task/Deadline.java @@ -0,0 +1,93 @@ +package manageezpz.model.task; + +import java.time.format.DateTimeFormatter; + +/** + * A class that represents a Deadline task. + */ +public class Deadline extends Task { + protected String type; + protected Description description; + private Date date; + private Time time; + + /** + * Constructor to initialize an instance of Deadline class with task + * description, date and time. + * + * @param taskDescription Description of the task. + * @param date Date by which the Deadline task needs to be completed. + * @param time Time by which the Deadline task needs to be completed. + */ + public Deadline(Description taskDescription, Date date, Time time) { + this.type = "deadline"; + this.description = taskDescription; + this.date = date; + this.time = time; + } + + /** + * Constructor to initialize an instance of Deadline class with an existing + * Deadline object. + * + * @param deadline Deadline task. + */ + public Deadline(Deadline deadline) { + this.type = deadline.getType(); + this.description = deadline.getDescription(); + this.date = deadline.getDate(); + this.time = deadline.getTime(); + this.isDone = deadline.isDone(); + this.priority = deadline.getPriority(); + this.assignees = deadline.getAssignees(); + } + + public Date getDate() { + return this.date; + } + + public Time getTime() { + return this.time; + } + + public void setDescription(Description description) { + this.description = description; + } + + public void setDate(Date date) { + this.date = date; + } + + public void setTime(Time time) { + this.time = time; + } + + @Override + public String getType() { + return this.type; + } + + @Override + public Description getDescription() { + return this.description; + } + + @Override + public String getDateTime() { + return "by " + date.format(DateTimeFormatter.ofPattern("MMM dd yyyy")) + + " " + time.format(DateTimeFormatter.ofPattern("h:mm a")); + } + + /** + * Returns the string representation of a Deadline task. + * + * @return The string representation of the Deadline task, consisting of its + * description and formatted date and time. + */ + @Override + public String toString() { + return "[D]" + super.toString() + getDescription() + + " (by: " + date.format(DateTimeFormatter.ofPattern("MMM dd yyyy")) + + " " + time.format(DateTimeFormatter.ofPattern("h:mm a")) + ")"; + } +} diff --git a/src/main/java/manageezpz/model/task/Description.java b/src/main/java/manageezpz/model/task/Description.java new file mode 100644 index 00000000000..d640c6c1710 --- /dev/null +++ b/src/main/java/manageezpz/model/task/Description.java @@ -0,0 +1,56 @@ +package manageezpz.model.task; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.util.AppUtil.checkArgument; + +public class Description { + public static final String MESSAGE_CONSTRAINTS = "Description should not be blank!"; + + public final String description; + + /** + * Constructs a {@code Description}. + * + * @param description A valid description. + */ + public Description(String description) { + requireNonNull(description); + checkArgument(isValidDescription(description), MESSAGE_CONSTRAINTS); + this.description = description; + } + + /** + * Checks if a given string is a valid description. + * @param test the description to be checked. + * @return true if a given string is a valid description, false otherwise. + */ + public static boolean isValidDescription(String test) { + return !(test.trim().isEmpty()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return description; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Description // instanceof handles nulls + && description.equals(((Description) other).description)); // state check + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return description.hashCode(); + } +} diff --git a/src/main/java/manageezpz/model/task/Event.java b/src/main/java/manageezpz/model/task/Event.java new file mode 100644 index 00000000000..d05d8654dd3 --- /dev/null +++ b/src/main/java/manageezpz/model/task/Event.java @@ -0,0 +1,107 @@ +package manageezpz.model.task; + +import java.time.format.DateTimeFormatter; + +/** + * A class that represents an Event task. + */ +public class Event extends Task { + protected String type; + protected Description description; + private Date date; + private Time startTime; + private Time endTime; + + /** + * Constructor to initialize an instance of Event class with task + * description, date, start time and end time. + * + * @param taskDescription Description of the task. + * @param date Date at which the Event task is taking place. + * @param startTime Start time of the Event task. + * @param endTime End time of the Event task. + */ + public Event(Description taskDescription, Date date, Time startTime, Time endTime) { + this.type = "event"; + this.description = taskDescription; + this.date = date; + this.startTime = startTime; + this.endTime = endTime; + } + + /** + * Constructor to initialize an instance of Event class with an existing + * Event object. + * + * @param event Event task + */ + public Event(Event event) { + this.type = event.getType(); + this.description = event.getDescription(); + this.date = event.getDate(); + this.startTime = event.getStartTime(); + this.endTime = event.getEndTime(); + this.isDone = event.isDone(); + this.priority = event.getPriority(); + this.assignees = event.getAssignees(); + } + + public Date getDate() { + return date; + } + + public Time getStartTime() { + return startTime; + } + + public Time getEndTime() { + return endTime; + } + + @Override + public String getType() { + return this.type; + } + + @Override + public Description getDescription() { + return this.description; + } + + public void setDescription(Description description) { + this.description = description; + } + + public void setDate(Date date) { + this.date = date; + } + + public void setStartTime(Time startTime) { + this.startTime = startTime; + } + + public void setEndTime(Time endTime) { + this.endTime = endTime; + } + + @Override + public String getDateTime() { + return "at " + date.format(DateTimeFormatter.ofPattern("MMM dd yyyy")) + + " " + startTime.format(DateTimeFormatter.ofPattern("h:mm a")) + " to" + + " " + endTime.format(DateTimeFormatter.ofPattern("h:mm a")); + } + + /** + * Returns the string representation of an Event task. + * + * @return The string representation of the event, consisting of its + * description, formatted date and formatted start and end time. + */ + @Override + public String toString() { + return "[E]" + super.toString() + getDescription() + + " (at: " + date.format(DateTimeFormatter.ofPattern("MMM dd yyyy")) + + " " + startTime.format(DateTimeFormatter.ofPattern("h:mm a")) + " to" + + " " + endTime.format(DateTimeFormatter.ofPattern("h:mm a")) + ")"; + } +} diff --git a/src/main/java/manageezpz/model/task/Priority.java b/src/main/java/manageezpz/model/task/Priority.java new file mode 100644 index 00000000000..4fb375b46c2 --- /dev/null +++ b/src/main/java/manageezpz/model/task/Priority.java @@ -0,0 +1,27 @@ +package manageezpz.model.task; + +/** + * An enum class that represents the priority of a given Task. + */ +public enum Priority { + HIGH(0), + MEDIUM(1), + LOW(2), + NONE(3); + + private final int value; + + /** + * Constructor to initialize an instance of Priority enumeration + * with value field. + * + * @param value Value of the Priority. + * */ + Priority(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/manageezpz/model/task/Task.java b/src/main/java/manageezpz/model/task/Task.java new file mode 100644 index 00000000000..9a7df77a0c8 --- /dev/null +++ b/src/main/java/manageezpz/model/task/Task.java @@ -0,0 +1,155 @@ +package manageezpz.model.task; + +import java.util.ArrayList; +import java.util.List; + +import manageezpz.model.person.Person; + +/** + * An abstract class that represents the tasks a user could create. + * A Task object would correspond to a task inputted + * by a user, either a Todo, Deadline or Event. + */ +public abstract class Task { + protected boolean isDone = false; + protected Priority priority = Priority.NONE; + + // Data fields + protected List assignees = new ArrayList<>(); + + /** + * Constructor to initialize an instance of Task class. + * + * {@code Date taskDate} has a default value that will be changed if the + * object inheriting the Task object is a Deadline or Event object. + * + */ + public Task() { + } + + /** + * Checks if the task is done or not. + * @return true if task is done, false otherwise. + */ + public boolean isDone() { + return isDone; + } + + public abstract String getType(); + + public abstract Description getDescription(); + + public abstract String getDateTime(); + + public String getStatusIcon() { + return this.isDone() ? "X" : " "; + } + + public Priority getPriority() { + return this.priority; + } + + public List getAssignees() { + return this.assignees; + } + + public void setTaskDone() { + this.isDone = true; + } + + public void setTaskNotDone() { + this.isDone = false; + } + + public void setPriority(String priority) { + this.priority = Priority.valueOf(priority); + } + + public void setPriority(Priority priority) { + this.priority = priority; + } + + /** + * Adds a Person to the Task List. + * @param person the person to be added. + */ + public void addAssignees(Person person) { + this.assignees.add(person); + } + + /** + * Checks if both Task have the same Description. + * @param otherTask the task to be checked against. + * @return true if both task are the same, false otherwise. + */ + public boolean isSameTask(Task otherTask) { + if (otherTask == this) { + return true; + } + + return otherTask != null + && otherTask.getDescription().equals(getDescription()); + } + + /** + * Used to assign a person to this Task. + * @param person the person to be assigned. + */ + public void assignedTo(Person person) { + assignees.add(person); + } + + /** + * Used to assign a new person to the specific index in the assignee list. + * @param index the index specified to the assignee list. + * @param newPerson the new person to be placed into the assignee list. + */ + public void assignedTo(int index, Person newPerson) { + assignees.set(index, newPerson); + } + + /** + * Used to deallocate a person from this Task. + * @param person The person to be deallocated. + */ + public void removeAssigned(Person person) { + assignees.remove(person); + } + + /** + * Checks whether the assignee is assigned to the task. + * @param assignee The assignee to be searched + * @return true if the assignee is assigned, false otherwise + */ + public boolean haveAssignees(String assignee) { + return assignees.stream() + .anyMatch(person -> person.getName().fullName.equals(assignee)); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "[" + getStatusIcon() + "] "; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof Task)) { + return false; + } + + Task otherTask = (Task) other; + return otherTask.getDescription().equals(getDescription()) + && otherTask.getStatusIcon().equals(getStatusIcon()); + } + +} diff --git a/src/main/java/manageezpz/model/task/TaskMultiplePredicate.java b/src/main/java/manageezpz/model/task/TaskMultiplePredicate.java new file mode 100644 index 00000000000..381dfdbf460 --- /dev/null +++ b/src/main/java/manageezpz/model/task/TaskMultiplePredicate.java @@ -0,0 +1,138 @@ +package manageezpz.model.task; + +import static manageezpz.logic.parser.CliSyntax.PREFIX_DEADLINE; +import static manageezpz.logic.parser.CliSyntax.PREFIX_EVENT; +import static manageezpz.logic.parser.CliSyntax.PREFIX_TODO; + +import java.util.List; +import java.util.function.Predicate; + +import manageezpz.commons.util.StringUtil; +import manageezpz.logic.parser.Prefix; + +/** + * The predicate to search tasks based on the properties given. + */ +public class TaskMultiplePredicate implements Predicate { + private final Prefix taskType; + private final List descriptions; + private final Date date; + private final Priority priority; + private final String assignee; + private final Boolean isMarked; + + /** + * The constructor for predicate. + * @param taskType The task type to search + * @param descriptions The description to search + * @param date The date of either the deadline or event + * @param priority The priority of the task + * @param assignee The employees assigned to the tasks + * @param isMarked Whether the task is marked + */ + public TaskMultiplePredicate(Prefix taskType, List descriptions, Date date, Priority priority, + String assignee, Boolean isMarked) { + this.taskType = taskType; + this.descriptions = descriptions; + this.date = date; + this.priority = priority; + this.assignee = assignee; + this.isMarked = isMarked; + + boolean isAtLeastOneNotNull = (this.taskType != null) || (this.descriptions != null) || (this.date != null) + || (this.priority != null) || (this.assignee != null) || (this.isMarked != null); + assert isAtLeastOneNotNull : "At least one search option should be specified"; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean test(Task task) { + // Checks if the specific search term is specified in the parameter, then check on the task provided. + // Defaults to true if not specified. + boolean hasTaskType = taskType != null ? checkIfHasSpecificTaskType(task) : true; + boolean hasKeyword = descriptions != null ? checkIfHasKeywords(task) : true; + boolean hasDate = date != null ? checkIfHasDate(task) : true; + boolean hasPriority = priority != null ? checkIfHasPriority(task) : true; + boolean hasAssignee = assignee != null ? checkIfHasAssignee(task) : true; + boolean hasIsMarked = isMarked != null ? checkedIfIsMarked(task) : true; + + return hasTaskType && hasKeyword && hasDate && hasPriority && hasAssignee && hasIsMarked; + } + + private boolean checkIfHasSpecificTaskType(Task task) { + boolean isTodo = taskType.equals(PREFIX_TODO) && task instanceof Todo; + boolean isDeadline = taskType.equals(PREFIX_DEADLINE) && task instanceof Deadline; + boolean isEvent = taskType.equals(PREFIX_EVENT) && task instanceof Event; + + return isTodo || isDeadline || isEvent; + } + + private boolean checkIfHasKeywords(Task task) { + String otherTaskDescription = task.getDescription().toString(); + return descriptions.stream() + .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(otherTaskDescription, keyword)); + } + + private boolean checkIfHasDate(Task task) { + if (task instanceof Todo) { + return false; + } else { + Date taskDate = getDateFromTask(task); + return taskDate.equals(date); + } + } + + private Date getDateFromTask(Task task) { + if (task instanceof Deadline) { + return ((Deadline) task).getDate(); + } else if (task instanceof Event) { + return ((Event) task).getDate(); + } else { + assert false : "checkIfHasDate() did not filter out the todo"; + return null; + } + } + + private boolean checkIfHasPriority(Task task) { + return task.getPriority().equals(priority); + } + + private boolean checkIfHasAssignee(Task task) { + return task.haveAssignees(assignee); + } + + private boolean checkedIfIsMarked(Task task) { + return task.isDone == isMarked.booleanValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof TaskMultiplePredicate) { + TaskMultiplePredicate pre = (TaskMultiplePredicate) obj; + boolean isSameTaskType = isSameOption(taskType, pre.taskType); + boolean isSameDescription = isSameOption(descriptions, pre.descriptions); + boolean isSameDate = isSameOption(date, pre.date); + boolean isSamePriority = isSameOption(priority, pre.priority); + boolean isSameAssignee = isSameOption(assignee, pre.assignee); + boolean isSameIsMarked = isSameOption(isMarked, pre.isMarked); + + return isSameTaskType + && isSameDescription && isSameDate && isSamePriority && isSameAssignee && isSameIsMarked; + } + return false; + } + + private boolean isSameOption(Object currentObj, Object otherObj) { + if (otherObj != null) { + return otherObj.equals(currentObj); + } + return currentObj == null; + } +} diff --git a/src/main/java/manageezpz/model/task/Time.java b/src/main/java/manageezpz/model/task/Time.java new file mode 100644 index 00000000000..7290b8b9150 --- /dev/null +++ b/src/main/java/manageezpz/model/task/Time.java @@ -0,0 +1,55 @@ +package manageezpz.model.task; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.util.AppUtil.checkArgument; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +public class Time { + public static final String MESSAGE_CONSTRAINTS = "Time should be in the format of HHmm, " + + "where it should only contain numbers that is 4 digits long.\n" + + "HH should only be between 00 and 23 and mm should only be between 00 and 59."; + + public static final String VALIDATION_REGEX = "\\d{4}"; + + private String time; + + /** + * Constructs a {@code Time}. + * @param time A valid time. + */ + public Time(String time) { + requireNonNull(time); + checkArgument(isValidTime(time), MESSAGE_CONSTRAINTS); + this.time = time; + } + + /** + * Checks if a given string is a valid time. + * @param time the time to be checked. + * @return true if a given string is a valid time, false otherwise. + */ + public static boolean isValidTime(String time) { + return time.matches(VALIDATION_REGEX) && time.matches("([01]?[0-9]|2[0-3])[0-5][0-9]"); + } + + public String getTime() { + return time; + } + + public LocalTime getParsedTime() { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HHmm"); + LocalTime parsedTime = LocalTime.parse(time, dtf); + return parsedTime; + } + + /** + * Formats the given time. + * @param dtf the DateTimeFormatter to be used to format the time. + * @return the formatted time. + */ + public String format(DateTimeFormatter dtf) { + return getParsedTime().format(dtf); + } +} diff --git a/src/main/java/manageezpz/model/task/Todo.java b/src/main/java/manageezpz/model/task/Todo.java new file mode 100644 index 00000000000..c42f23ee693 --- /dev/null +++ b/src/main/java/manageezpz/model/task/Todo.java @@ -0,0 +1,62 @@ +package manageezpz.model.task; + +/** + * A class that represents a Todo task. + */ +public class Todo extends Task { + protected String type; + protected Description description; + + /** + * Constructor to initialize an instance of Todo class with task description. + * + * @param taskDescription Description of the task. + */ + public Todo(Description taskDescription) { + this.type = "todo"; + this.description = taskDescription; + } + + /** + * Constructor to initialize an instance of Todo class with an existing Todo object. + * + * @param todo Todo task. + */ + public Todo(Todo todo) { + this.type = todo.getType(); + this.description = todo.getDescription(); + this.isDone = todo.isDone(); + this.priority = todo.getPriority(); + this.assignees = todo.getAssignees(); + } + + @Override + public String getType() { + return this.type; + } + + @Override + public Description getDescription() { + return this.description; + } + + @Override + public String getDateTime() { + return null; + } + + public void setDescription(Description description) { + this.description = description; + } + + /** + * Returns the string representation of a Todo task. + * + * @return The string representation of the Todo task, consisting of its + * description. + */ + @Override + public String toString() { + return "[T]" + super.toString() + getDescription(); + } +} diff --git a/src/main/java/manageezpz/model/task/UniqueTaskList.java b/src/main/java/manageezpz/model/task/UniqueTaskList.java new file mode 100644 index 00000000000..2725a6f371d --- /dev/null +++ b/src/main/java/manageezpz/model/task/UniqueTaskList.java @@ -0,0 +1,273 @@ +package manageezpz.model.task; + +import static java.util.Objects.requireNonNull; +import static manageezpz.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Iterator; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import manageezpz.model.person.Person; +import manageezpz.model.task.exceptions.DuplicateTaskException; +import manageezpz.model.task.exceptions.InvalidTaskTypeException; +import manageezpz.model.task.exceptions.TaskNotFoundException; + +/** + * A list of Task that enforces uniqueness between its elements and does not allow nulls. + * A task is considered unique by comparing using {@code Task#isSameTask(Task)}. As such, adding and updating of + * Task uses Task#isSameTask(Task) for equality to ensure that the task being added or updated is + * unique in terms of identity in the UniqueTaskList. However, the removal of a Task uses Task#equals(Object) + * to ensure that the Task with exactly the same fields will be removed. + * + * Supports a minimal set of list operations. + * + * @see Task#isSameTask(Task) + */ +public class UniqueTaskList implements Iterable { + private final ObservableList internalList = FXCollections.observableArrayList(); + private final ObservableList internalUnmodifiableList = + FXCollections.unmodifiableObservableList(internalList); + + /** + * Checks if the list contains an equivalent Task as the given argument. + * @param toCheck the task to be checked. + * @return true if the list contains the specified task, false otherwise. + */ + public boolean contains(Task toCheck) { + requireNonNull(toCheck); + return internalList.stream().anyMatch(toCheck::isSameTask); + } + + /** + * Adds a task to the list. + * The task must not already exist in the list. + * @param toAdd the task to be added. + */ + public void add(Task toAdd) { + requireNonNull(toAdd); + if (contains(toAdd)) { + throw new DuplicateTaskException(); + } + internalList.add(toAdd); + } + + /** + * Replaces the task {@code target} in the list with {@code editedTask}. + * {@code target} must exist in the list. + * The task identity of {@code editedTask} must not be the same as another existing task in the list. + * @param target the task to be replaced. + * @param editedTask the new task to replace target. + */ + public void setTask(Task target, Task editedTask) { + requireAllNonNull(target, editedTask); + + int index = internalList.indexOf(target); + if (index == -1) { + throw new TaskNotFoundException(); + } + + if (!target.isSameTask(editedTask) && contains(editedTask)) { + throw new DuplicateTaskException(); + } + + internalList.set(index, editedTask); + } + + /** + * Updates the task with the edited person. + * @param toUpdate the task to be updated. + * @param assigneesIndex the index of the person in List of assignees. + * @param editedPerson the edited person. + */ + public void updateTaskWithEditedPerson(Task toUpdate, int assigneesIndex, Person editedPerson) { + requireAllNonNull(toUpdate, assigneesIndex, editedPerson); + + Task updatedTask = duplicateTask(toUpdate); + updatedTask.assignedTo(assigneesIndex, editedPerson); + + setTask(toUpdate, updatedTask); + } + + /** + * Marks a task in the list as done. + * The task must already exist in the list. + * @param toMark the task to be marked. + * @return the marked task. + */ + public Task markTask(Task toMark) { + requireNonNull(toMark); + + Task markedTask = duplicateTask(toMark); + markedTask.setTaskDone(); + + setTask(toMark, markedTask); + + return markedTask; + } + + + /** + * unMarks a task in the list as not done yet. + * The task must already exist in the list. + * @param toUnmark the task to be unmarked. + * @return the unamrked task. + */ + public Task unmarkTask(Task toUnmark) { + requireNonNull(toUnmark); + + Task unmarkedTask = duplicateTask(toUnmark); + unmarkedTask.setTaskNotDone(); + + setTask(toUnmark, unmarkedTask); + + return unmarkedTask; + } + + /** + * Tags a priority to the task. + * @param toTagPriority the task to be tagged. + * @param priority the priority specified to be tagged to the task. + * @return the tagged task. + */ + public Task tagPriorityToTask(Task toTagPriority, Priority priority) { + requireNonNull(toTagPriority); + requireNonNull(priority); + + Task taggedPriorityTask = duplicateTask(toTagPriority); + taggedPriorityTask.setPriority(priority); + + setTask(toTagPriority, taggedPriorityTask); + + return taggedPriorityTask; + } + + /** + * Tags an employee to the task. + * @param toTagEmployee the task to be tagged. + * @param person the employee to be tagged to the task. + * @return the tagged task. + */ + public Task tagEmployeeToTask(Task toTagEmployee, Person person) { + requireNonNull(toTagEmployee); + requireNonNull(person); + + Task taggedEmployeeTask = duplicateTask(toTagEmployee); + taggedEmployeeTask.assignedTo(person); + + setTask(toTagEmployee, taggedEmployeeTask); + + return taggedEmployeeTask; + } + + /** + * * Untags an employee to the task. + * @param toUntagEmployee the task to be untagged. + * @param person the person to be untagged from the task. + * @return the untagged task. + */ + public Task untagEmployeeFromTask(Task toUntagEmployee, Person person) { + requireNonNull(toUntagEmployee); + requireNonNull(person); + + Task untaggedEmployeeTask = duplicateTask(toUntagEmployee); + untaggedEmployeeTask.removeAssigned(person); + + setTask(toUntagEmployee, untaggedEmployeeTask); + + return untaggedEmployeeTask; + } + + private Task duplicateTask(Task task) { + if (task instanceof Todo) { + return new Todo((Todo) task); + } else if (task instanceof Deadline) { + return new Deadline((Deadline) task); + } else if (task instanceof Event) { + return new Event((Event) task); + } else { + // The else statement should not be reached since there are + // only three types of tasks, i.e., todo, deadline and event + throw new InvalidTaskTypeException(); + } + } + + /** + * Removes the equivalent task from the list. + * The task must exist in the list. + * @param toRemove the task to be removed. + */ + public void remove(Task toRemove) { + requireNonNull(toRemove); + if (!internalList.remove(toRemove)) { + throw new TaskNotFoundException(); + } + } + + public void setTasks(UniqueTaskList replacement) { + requireNonNull(replacement); + internalList.setAll(replacement.internalList); + } + + /** + * Replaces the contents of this list with {@code tasks}. + * {@code tasks} must not contain duplicate tasks. + * @param tasks the content of the new list. + */ + public void setTasks(List tasks) { + requireAllNonNull(tasks); + if (!tasksAreUnique(tasks)) { + throw new DuplicateTaskException(); + } + + internalList.setAll(tasks); + } + + /** + * Returns the backing list as an unmodifiable {@code ObservableList}. + * @return the unmodifiable task list. + */ + public ObservableList asUnmodifiableObservableList() { + return internalUnmodifiableList; + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueTaskList // instanceof handles nulls + && internalList.equals(((UniqueTaskList) other).internalList)); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return internalList.hashCode(); + } + + /** + * Returns true if {@code persons} contains only unique Task. + */ + private boolean tasksAreUnique(List tasks) { + for (int i = 0; i < tasks.size() - 1; i++) { + for (int j = i + 1; j < tasks.size(); j++) { + if (tasks.get(i).isSameTask(tasks.get(j))) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/manageezpz/model/task/exceptions/DuplicateTaskException.java b/src/main/java/manageezpz/model/task/exceptions/DuplicateTaskException.java new file mode 100644 index 00000000000..e6e7185e5af --- /dev/null +++ b/src/main/java/manageezpz/model/task/exceptions/DuplicateTaskException.java @@ -0,0 +1,11 @@ +package manageezpz.model.task.exceptions; + +/** + * Signals that the operation will result in duplicate Task (Task are considered duplicates if they have the same + * description). + */ +public class DuplicateTaskException extends RuntimeException { + public DuplicateTaskException() { + super("Operation would result in duplicate Task"); + } +} diff --git a/src/main/java/manageezpz/model/task/exceptions/InvalidTaskTypeException.java b/src/main/java/manageezpz/model/task/exceptions/InvalidTaskTypeException.java new file mode 100644 index 00000000000..bb4ae2de40c --- /dev/null +++ b/src/main/java/manageezpz/model/task/exceptions/InvalidTaskTypeException.java @@ -0,0 +1,7 @@ +package manageezpz.model.task.exceptions; + +/** + * Signals that the operation is unable to read the type of a Task. + */ +public class InvalidTaskTypeException extends RuntimeException { +} diff --git a/src/main/java/manageezpz/model/task/exceptions/TaskNotFoundException.java b/src/main/java/manageezpz/model/task/exceptions/TaskNotFoundException.java new file mode 100644 index 00000000000..f9ddc21bba0 --- /dev/null +++ b/src/main/java/manageezpz/model/task/exceptions/TaskNotFoundException.java @@ -0,0 +1,7 @@ +package manageezpz.model.task.exceptions; + +/** + * Signals that the operation is unable to find the specified Task. + */ +public class TaskNotFoundException extends RuntimeException { +} diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/manageezpz/model/tasktag/Tag.java similarity index 77% rename from src/main/java/seedu/address/model/tag/Tag.java rename to src/main/java/manageezpz/model/tasktag/Tag.java index b0ea7e7dad7..8baab608d28 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/manageezpz/model/tasktag/Tag.java @@ -1,10 +1,10 @@ -package seedu.address.model.tag; +package manageezpz.model.tasktag; import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; +import static manageezpz.commons.util.AppUtil.checkArgument; /** - * Represents a Tag in the address book. + * Represents a Tag in the Task List. * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)} */ public class Tag { @@ -26,12 +26,17 @@ public Tag(String tagName) { } /** - * Returns true if a given string is a valid tag name. + * Check if a given string is a valid tag name. + * @param test the tag name to be checked. + * @return true if the tag is valid, false otherwise. */ public static boolean isValidTagName(String test) { return test.matches(VALIDATION_REGEX); } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { return other == this // short circuit if same object @@ -39,6 +44,9 @@ public boolean equals(Object other) { && tagName.equals(((Tag) other).tagName)); // state check } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return tagName.hashCode(); diff --git a/src/main/java/manageezpz/model/util/SampleDataUtil.java b/src/main/java/manageezpz/model/util/SampleDataUtil.java new file mode 100644 index 00000000000..9f2f84fe3d3 --- /dev/null +++ b/src/main/java/manageezpz/model/util/SampleDataUtil.java @@ -0,0 +1,67 @@ +package manageezpz.model.util; + +import manageezpz.model.AddressBook; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.Person; +import manageezpz.model.person.Phone; +import manageezpz.model.task.Date; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Description; +import manageezpz.model.task.Event; +import manageezpz.model.task.Task; +import manageezpz.model.task.Time; +import manageezpz.model.task.Todo; + +/** + * Contains utility methods for populating {@code AddressBook} with sample data. + */ +public class SampleDataUtil { + public static Person[] getSamplePersons() { + return new Person[] { + new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), 0), + new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), 0), + new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), 0), + new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), 0), + new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), 0), + new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), 0), + new Person(new Name("Peter Tan"), new Phone("95214839"), new Email("petertan@example.com"), 0), + new Person(new Name("Jack Koh"), new Phone("86201478"), new Email("jackkoh@example.com"), 0), + new Person(new Name("Zachery Lam"), new Phone("87412058"), new Email("zacherylam@example.com"), 0), + new Person(new Name("Jason Lim"), new Phone("90321458"), new Email("jasonlim@example.com"), 0), + }; + } + + public static Task[] getSampleTasks() { + return new Task[] { + new Todo(new Description("Review Monthly Finance KPI")), + new Deadline(new Description("Finish Client Proposal"), + new Date("2022-03-15"), new Time("1800")), + new Event(new Description("Meeting with Client"), new Date("2022-03-15"), + new Time("1300"), new Time("1400")), + new Todo(new Description("Call Representative of Company XYZ")), + new Deadline(new Description("Submit Proposal"), + new Date("2022-04-08"), new Time("1800")), + new Event(new Description("Meeting with HR"), new Date("2022-03-16"), + new Time("1400"), new Time("1500")), + new Deadline(new Description("Submit Sales Report"), + new Date("2022-06-15"), new Time("1800")), + new Deadline(new Description("Payout Employees"), + new Date("2022-04-30"), new Time("1900")), + new Event(new Description("Working lunch with Client"), new Date("2022-03-17"), + new Time("1200"), new Time("1400")), + new Todo(new Description("Review IT Report")), + }; + } + public static ReadOnlyAddressBook getSampleAddressBook() { + AddressBook sampleAb = new AddressBook(); + for (Person samplePerson : getSamplePersons()) { + sampleAb.addPerson(samplePerson); + } + for (Task sampleTask : getSampleTasks()) { + sampleAb.addTask(sampleTask); + } + return sampleAb; + } +} diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/manageezpz/storage/AddressBookStorage.java similarity index 78% rename from src/main/java/seedu/address/storage/AddressBookStorage.java rename to src/main/java/manageezpz/storage/AddressBookStorage.java index 4599182b3f9..393813ae261 100644 --- a/src/main/java/seedu/address/storage/AddressBookStorage.java +++ b/src/main/java/manageezpz/storage/AddressBookStorage.java @@ -1,25 +1,26 @@ -package seedu.address.storage; +package manageezpz.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.model.ReadOnlyAddressBook; /** - * Represents a storage for {@link seedu.address.model.AddressBook}. + * Represents a storage for {@link manageezpz.model.AddressBook}. */ public interface AddressBookStorage { /** * Returns the file path of the data file. + * @return Path representation of the data file. */ Path getAddressBookFilePath(); /** * Returns AddressBook data as a {@link ReadOnlyAddressBook}. - * Returns {@code Optional.empty()} if storage file is not found. + * @return {@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. */ diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/manageezpz/storage/JsonAdaptedPerson.java similarity index 60% rename from src/main/java/seedu/address/storage/JsonAdaptedPerson.java rename to src/main/java/manageezpz/storage/JsonAdaptedPerson.java index a6321cec2ea..085d4875174 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/manageezpz/storage/JsonAdaptedPerson.java @@ -1,21 +1,13 @@ -package seedu.address.storage; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; +package manageezpz.storage; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -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.tag.Tag; +import manageezpz.commons.exceptions.IllegalValueException; +import manageezpz.model.person.Email; +import manageezpz.model.person.Name; +import manageezpz.model.person.Person; +import manageezpz.model.person.Phone; /** * Jackson-friendly version of {@link Person}. @@ -27,23 +19,18 @@ class JsonAdaptedPerson { private final String name; private final String phone; private final String email; - private final String address; - private final List tagged = new ArrayList<>(); + private final int numOfTask; /** * Constructs a {@code JsonAdaptedPerson} with the given person details. */ @JsonCreator public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, - @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tagged") List tagged) { + @JsonProperty("email") String email, @JsonProperty("numOfTask") int numOfTask) { this.name = name; this.phone = phone; this.email = email; - this.address = address; - if (tagged != null) { - this.tagged.addAll(tagged); - } + this.numOfTask = numOfTask; } /** @@ -53,10 +40,7 @@ public JsonAdaptedPerson(Person source) { name = source.getName().fullName; phone = source.getPhone().value; email = source.getEmail().value; - address = source.getAddress().value; - tagged.addAll(source.getTags().stream() - .map(JsonAdaptedTag::new) - .collect(Collectors.toList())); + numOfTask = source.getNumOfTasks(); } /** @@ -65,11 +49,6 @@ public JsonAdaptedPerson(Person source) { * @throws IllegalValueException if there were any data constraints violated in the adapted person. */ public Person toModelType() throws IllegalValueException { - final List personTags = new ArrayList<>(); - for (JsonAdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - if (name == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName())); } @@ -89,21 +68,14 @@ public Person toModelType() throws IllegalValueException { if (email == null) { throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName())); } + if (numOfTask < 0) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Person.class.getSimpleName())); + } if (!Email.isValidEmail(email)) { throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS); } final Email modelEmail = new Email(email); - - if (address == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName())); - } - if (!Address.isValidAddress(address)) { - throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS); - } - final Address modelAddress = new Address(address); - - final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); + return new Person(modelName, modelPhone, modelEmail, numOfTask); } } diff --git a/src/main/java/manageezpz/storage/JsonAdaptedTask.java b/src/main/java/manageezpz/storage/JsonAdaptedTask.java new file mode 100644 index 00000000000..30949230a82 --- /dev/null +++ b/src/main/java/manageezpz/storage/JsonAdaptedTask.java @@ -0,0 +1,297 @@ +package manageezpz.storage; + +import java.util.List; +import java.util.StringJoiner; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import javafx.collections.ObservableList; +import manageezpz.commons.exceptions.IllegalValueException; +import manageezpz.model.person.Person; +import manageezpz.model.task.Date; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Description; +import manageezpz.model.task.Event; +import manageezpz.model.task.Priority; +import manageezpz.model.task.Task; +import manageezpz.model.task.Time; +import manageezpz.model.task.Todo; +import manageezpz.model.tasktag.Tag; + +/** + * Jackson-friendly version of {@link Task}. + */ +class JsonAdaptedTask { + + public static final String INVALID_DESCRIPTION_MESSAGE_FORMAT = "Task's description is invalid!"; + public static final String NULL_DESCRIPTION_MESSAGE_FORMAT = "Task's description cannot be null!"; + public static final String INCORRECT_TYPE_MESSAGE_FORMAT = "Task's type is incorrect!"; + public static final String NULL_TYPE_MESSAGE_FORMAT = "Task's type cannot be null!"; + public static final String NULL_STATUS_MESSAGE_FORMAT = "Task's status cannot be null!"; + public static final String INVALID_STATUS_MESSAGE_FORMAT = "Task's status is invalid!"; + public static final String NULL_TAG_MESSAGE_FORMAT = "Task's tag cannot be null!"; + public static final String NULL_PRIORITY_MESSAGE_FORMAT = "Task's priority cannot be null!"; + public static final String INVALID_PRIORITY_MESSAGE_FORMAT = "Task's priority is invalid!"; + + public static final String NULL_DEADLINE_DATE_MESSAGE_FORMAT = "Deadline Task's date cannot be null!"; + public static final String INVALID_DEADLINE_DATE_MESSAGE_FORMAT = "Deadline Task's date is invalid!"; + public static final String NULL_DEADLINE_TIME_MESSAGE_FORMAT = "Deadline Task's time cannot be null!"; + public static final String INVALID_DEADLINE_TIME_MESSAGE_FORMAT = "Deadline Task's time is invalid!"; + + public static final String NULL_EVENT_DATE_MESSAGE_FORMAT = "Event Task's date cannot be null!"; + public static final String INVALID_EVENT_DATE_MESSAGE_FORMAT = "Event Task's date is invalid!"; + public static final String NULL_EVENT_START_TIME_MESSAGE_FORMAT = "Event Task's start time cannot be null!"; + public static final String INVALID_EVENT_START_TIME_MESSAGE_FORMAT = "Event Task's start time is invalid!"; + public static final String NULL_EVENT_END_TIME_MESSAGE_FORMAT = "Event Task's end time cannot be null!"; + public static final String INVALID_EVENT_END_TIME_MESSAGE_FORMAT = "Event Task's end time is invalid!"; + + private final String description; + private final String type; + private final String date; + private String deadlineTime; + private String eventStartTime; + private String eventEndTime; + private String status; + private String tag; + private String priority; + + /** + * Constructs a {@code JsonAdaptedTask} with the given person details. + */ + @JsonCreator + public JsonAdaptedTask(@JsonProperty("type") String type, @JsonProperty("status") String status, + @JsonProperty("description") String description, + @JsonProperty("date") String date, @JsonProperty("deadlineTime") String deadlineTime, + @JsonProperty("eventStartTime") String eventStartTime, + @JsonProperty("eventEndTime") String eventEndTime, + @JsonProperty("tag") String tag, + @JsonProperty("priority") String priority) { + this.description = description; + this.status = status; + this.type = type; + this.date = date; + this.deadlineTime = deadlineTime; + this.eventStartTime = eventStartTime; + this.eventEndTime = eventEndTime; + this.tag = tag; + this.priority = priority; + } + + /** + * Converts a given {@code Task} into this class for Jackson use. + */ + + public JsonAdaptedTask(Task source) { + description = source.getDescription().toString(); // Generally for all tasks + type = source.getType(); // Generally for all tasks + status = source.getStatusIcon(); // Generally for all tasks + this.priority = source.getPriority().name(); // Generally for all tasks + if (source instanceof Deadline) { + this.date = ((Deadline) source).getDate().getDate(); // For Deadline + this.deadlineTime = ((Deadline) source).getTime().getTime(); // For Deadline + } else if ((source instanceof Event)) { + this.date = ((Event) source).getDate().getDate(); // For Event + this.eventStartTime = ((Event) source).getStartTime().getTime(); // For Event + this.eventEndTime = ((Event) source).getEndTime().getTime(); // For Event + } else { + this.date = ""; + this.deadlineTime = ""; + this.eventStartTime = ""; + this.eventEndTime = ""; + } + List personList = source.getAssignees(); + StringJoiner joiner = new StringJoiner(", "); + personList.forEach(item -> joiner.add(item.getName().toString())); + this.tag = joiner.toString(); + } + + /** + * Converts this Jackson-friendly adapted person object into the model's {@code Task} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted person. + */ + public Task toModelType(ObservableList persons) throws IllegalValueException { + handleGeneralNullChecks(description, type, status, tag, priority); + Description desc = new Description(description); + boolean isDone = status.equals("X"); + if (type.equals("todo")) { + Todo newTodo = new Todo(desc); + handleLoad(newTodo, isDone, priority, tag, persons); + return newTodo; + } else if (type.equals("deadline")) { + handleDeadlineNullChecks(date, deadlineTime); + Date currDeadlineDate = new Date(date); + Time currDeadlineTime = new Time(deadlineTime); + Deadline newDeadline = new Deadline(desc, currDeadlineDate, currDeadlineTime); + handleLoad(newDeadline, isDone, priority, tag, persons); + return newDeadline; + } else { + handleEventNullChecks(date, eventStartTime, eventEndTime); + Date currEventDate = new Date(date); + Time currEventStartTime = new Time(eventStartTime); + Time currEventEndTime = new Time(eventEndTime); + Event newEvent = new Event(desc, currEventDate, currEventStartTime, currEventEndTime); + handleLoad(newEvent, isDone, priority, tag, persons); + return newEvent; + } + } + + public void handleLoad(Task task, boolean isDone, String priority, + String tag, ObservableList persons) { + if (isDone) { + task.setTaskDone(); + } + if (priority != null && !priority.isEmpty()) { + task.setPriority(priority); + } + String[] tagList = tag.split(","); + for (int i = 0; i < tagList.length; i++) { + String currentTag = tagList[i].trim(); + for (int j = 0; j < persons.size(); j++) { + Person matchedPerson; + if (persons.get(j).getName().toString().equals(currentTag)) { + matchedPerson = persons.get(j); + task.addAssignees(matchedPerson); + } + } + } + } + + public void handleGeneralNullChecks(String description, String type, String status, String tag, String priority) + throws IllegalValueException { + handleDescriptionChecks(description); + handleTypeChecks(type); + handleStatusChecks(status); + handleTagChecks(tag); + handlePriorityChecks(priority); + } + + public void handleDescriptionChecks(String description) throws IllegalValueException { + if (description == null) { + throw new IllegalValueException(String.format(NULL_DESCRIPTION_MESSAGE_FORMAT, + Description.class.getSimpleName())); + } + + if (!Description.isValidDescription(description)) { + throw new IllegalValueException(String.format(INVALID_DESCRIPTION_MESSAGE_FORMAT, + Description.class.getSimpleName())); + } + } + + public void handleTypeChecks(String type) throws IllegalValueException { + if (type == null) { + throw new IllegalValueException(String.format(NULL_TYPE_MESSAGE_FORMAT, Task.class.getSimpleName())); + } + + if (!(type.equals("todo") || type.equals("deadline") || type.equals("event"))) { + throw new IllegalValueException(String.format(INCORRECT_TYPE_MESSAGE_FORMAT, Task.class.getSimpleName())); + } + } + + public void handleStatusChecks(String status) throws IllegalValueException { + if (status == null) { + throw new IllegalValueException(String.format(NULL_STATUS_MESSAGE_FORMAT, Task.class.getSimpleName())); + } + + if (!(status.equals(" ") || status.equals("X"))) { + throw new IllegalValueException(String.format(INVALID_STATUS_MESSAGE_FORMAT, Task.class.getSimpleName())); + } + } + + public void handleTagChecks(String tag) throws IllegalValueException { + if (tag == null) { + throw new IllegalValueException(String.format(NULL_TAG_MESSAGE_FORMAT, Tag.class.getSimpleName())); + } + } + + public void handlePriorityChecks(String priority) throws IllegalValueException { + if (priority == null) { + throw new IllegalValueException(String.format(NULL_PRIORITY_MESSAGE_FORMAT, + Priority.class.getSimpleName())); + } + + if (!(priority.equals("NONE") || priority.equals("LOW") + || priority.equals("MEDIUM") || priority.equals("HIGH"))) { + throw new IllegalValueException(String.format(INVALID_PRIORITY_MESSAGE_FORMAT, + Priority.class.getSimpleName())); + } + } + + public void handleDeadlineNullChecks(String date, String deadlineTime) throws IllegalValueException { + handleDateChecks(date, type); + handleTimeChecks(deadlineTime, type, "deadlineTime"); + } + + public void handleEventNullChecks(String date, String eventStartTime, String eventEndTime) + throws IllegalValueException { + handleDateChecks(date, type); + handleTimeChecks(eventStartTime, type, "eventStartTime"); + handleTimeChecks(eventEndTime, type, "eventEndTime"); + } + + public void handleDateChecks(String date, String type) throws IllegalValueException { + if (date == null) { + if (type.equals("deadline")) { + throw new IllegalValueException(String.format(NULL_DEADLINE_DATE_MESSAGE_FORMAT, + Date.class.getSimpleName())); + } + if (type.equals("event")) { + throw new IllegalValueException(String.format(NULL_EVENT_DATE_MESSAGE_FORMAT, + Date.class.getSimpleName())); + } + } + + if (!Date.isValidDate(date)) { + if (type.equals("deadline")) { + throw new IllegalValueException(String.format(INVALID_DEADLINE_DATE_MESSAGE_FORMAT, + Date.class.getSimpleName())); + } + if (type.equals("event")) { + throw new IllegalValueException(String.format(INVALID_EVENT_DATE_MESSAGE_FORMAT, + Date.class.getSimpleName())); + } + } + } + + public void handleTimeChecks(String time, String type, String timeIdentifier) throws IllegalValueException { + if (time == null) { + if (type.equals("deadline")) { + throw new IllegalValueException(String.format(NULL_DEADLINE_TIME_MESSAGE_FORMAT, + Date.class.getSimpleName())); + } + if (type.equals("event")) { + handleEventTimeNullIdentifier(timeIdentifier); + } + } + if (!Time.isValidTime(time)) { + if (type.equals("deadline")) { + throw new IllegalValueException(String.format(INVALID_DEADLINE_TIME_MESSAGE_FORMAT, + Time.class.getSimpleName())); + } + if (type.equals("event")) { + handleEventTimeInvalidIdentifier(timeIdentifier); + } + } + } + + public void handleEventTimeNullIdentifier(String timeIdentifier) throws IllegalValueException { + if (timeIdentifier.equals("eventStartTime")) { + throw new IllegalValueException(String.format(NULL_EVENT_START_TIME_MESSAGE_FORMAT, + Time.class.getSimpleName())); + } else if (timeIdentifier.equals("eventEndTime")) { + throw new IllegalValueException(String.format(NULL_EVENT_END_TIME_MESSAGE_FORMAT, + Time.class.getSimpleName())); + } + } + + public void handleEventTimeInvalidIdentifier(String timeIdentifier) throws IllegalValueException { + if (timeIdentifier.equals("eventStartTime")) { + throw new IllegalValueException(String.format(INVALID_EVENT_START_TIME_MESSAGE_FORMAT, + Time.class.getSimpleName())); + } else if (timeIdentifier.equals("eventEndTime")) { + throw new IllegalValueException(String.format(INVALID_EVENT_END_TIME_MESSAGE_FORMAT, + Time.class.getSimpleName())); + } + } +} diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/manageezpz/storage/JsonAddressBookStorage.java similarity index 86% rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java rename to src/main/java/manageezpz/storage/JsonAddressBookStorage.java index dfab9daaa0d..15d42057bac 100644 --- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java +++ b/src/main/java/manageezpz/storage/JsonAddressBookStorage.java @@ -1,4 +1,4 @@ -package seedu.address.storage; +package manageezpz.storage; import static java.util.Objects.requireNonNull; @@ -7,12 +7,12 @@ 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.exceptions.IllegalValueException; -import seedu.address.commons.util.FileUtil; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.ReadOnlyAddressBook; +import manageezpz.commons.core.LogsCenter; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.commons.exceptions.IllegalValueException; +import manageezpz.commons.util.FileUtil; +import manageezpz.commons.util.JsonUtil; +import manageezpz.model.ReadOnlyAddressBook; /** * A class to access AddressBook data stored as a json file on the hard disk. diff --git a/src/main/java/manageezpz/storage/JsonSerializableAddressBook.java b/src/main/java/manageezpz/storage/JsonSerializableAddressBook.java new file mode 100644 index 00000000000..addaf0db1aa --- /dev/null +++ b/src/main/java/manageezpz/storage/JsonSerializableAddressBook.java @@ -0,0 +1,101 @@ +package manageezpz.storage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRootName; + +import manageezpz.commons.exceptions.IllegalValueException; +import manageezpz.model.AddressBook; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.person.Person; +import manageezpz.model.task.Task; + +/** + * An Immutable AddressBook that is serializable to JSON format. + */ +@JsonRootName(value = "addressbook") +class JsonSerializableAddressBook { + + public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; + public static final String MESSAGE_DUPLICATE_TASKS = "Tasks list contains duplicate task(s)."; + public static final String MESSAGE_INVALID_JSON_VALUE = "Fields in JSON files are incorrect."; + + private final List persons = new ArrayList<>(); + private final List tasks = new ArrayList<>(); + + /** + * Constructs a {@code JsonSerializableAddressBook} with the given persons. + */ + @JsonCreator + public JsonSerializableAddressBook(@JsonProperty("persons") List persons, + @JsonProperty("tasks") List tasks) { + this.persons.addAll(persons); + this.tasks.addAll(tasks); + } + + /** + * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use. + * + * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}. + */ + public JsonSerializableAddressBook(ReadOnlyAddressBook source) { + persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList())); + tasks.addAll(source.getTaskList().stream().map(JsonAdaptedTask::new).collect(Collectors.toList())); + } + + /** + * Converts this address book into the model's {@code AddressBook} object. + * + * @throws IllegalValueException if there were any data constraints violated. + */ + public AddressBook toModelType() throws IllegalValueException { + AddressBook addressBook = new AddressBook(); + HashMap hm = new HashMap<>(); + for (JsonAdaptedPerson jsonAdaptedPerson : persons) { + Person person = jsonAdaptedPerson.toModelType(); + if (addressBook.hasPerson(person)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON); + } + addressBook.addPerson(person); + hm.put(person, 0); + } + + for (JsonAdaptedTask jsonAdaptedTask : tasks) { + Task task = jsonAdaptedTask.toModelType(addressBook.getPersonList()); + if (addressBook.hasTask(task)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_TASKS); + } + addressBook.addTask(task); + } + + handleNumOfTask(addressBook.getTaskList(), addressBook.getPersonList(), hm); + + return addressBook; + } + + + public void handleNumOfTask(List taskList, List personList, HashMap hm) + throws IllegalValueException { + for (Task task : taskList) { + List assigneesList = task.getAssignees(); + for (int i = 0; i < assigneesList.size(); i++) { + Person currentPerson = assigneesList.get(i); + if (hm.containsKey(currentPerson)) { + hm.put(currentPerson, hm.get(currentPerson) + 1); + } + } + } + + for (Person person : personList) { + int numOfTask = hm.get(person); + if (numOfTask != person.getNumOfTasks()) { + throw new IllegalValueException(MESSAGE_INVALID_JSON_VALUE); + } + } + } +} diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/manageezpz/storage/JsonUserPrefsStorage.java similarity index 79% rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java rename to src/main/java/manageezpz/storage/JsonUserPrefsStorage.java index bc2bbad84aa..b99fc234f70 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/manageezpz/storage/JsonUserPrefsStorage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; +package manageezpz.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.JsonUtil; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.commons.util.JsonUtil; +import manageezpz.model.ReadOnlyUserPrefs; +import manageezpz.model.UserPrefs; /** * A class to access UserPrefs stored in the hard disk as a json file @@ -33,6 +33,7 @@ public Optional readUserPrefs() throws DataConversionException { /** * Similar to {@link #readUserPrefs()} * @param prefsFilePath location of the data. Cannot be null. + * @return {@code Optional.empty()} if User preferences file is not found. * @throws DataConversionException if the file format is not as expected. */ public Optional readUserPrefs(Path prefsFilePath) throws DataConversionException { diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/manageezpz/storage/Storage.java similarity index 73% rename from src/main/java/seedu/address/storage/Storage.java rename to src/main/java/manageezpz/storage/Storage.java index beda8bd9f11..2ad6ab39824 100644 --- a/src/main/java/seedu/address/storage/Storage.java +++ b/src/main/java/manageezpz/storage/Storage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; +package manageezpz.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.ReadOnlyUserPrefs; +import manageezpz.model.UserPrefs; /** * API of the Storage component diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/manageezpz/storage/StorageManager.java similarity index 84% rename from src/main/java/seedu/address/storage/StorageManager.java rename to src/main/java/manageezpz/storage/StorageManager.java index 6cfa0162164..3bd2f168177 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/manageezpz/storage/StorageManager.java @@ -1,15 +1,15 @@ -package seedu.address.storage; +package manageezpz.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; import java.util.logging.Logger; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import manageezpz.commons.core.LogsCenter; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.model.ReadOnlyAddressBook; +import manageezpz.model.ReadOnlyUserPrefs; +import manageezpz.model.UserPrefs; /** * Manages storage of AddressBook data in local storage. @@ -22,6 +22,8 @@ public class StorageManager implements Storage { /** * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}. + * @param addressBookStorage {@code AddressBookStorage} object to store your address book. + * @param userPrefsStorage {@code UserPrefStorage} object to store your user preferences. */ public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) { this.addressBookStorage = addressBookStorage; diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/manageezpz/storage/UserPrefsStorage.java similarity index 62% rename from src/main/java/seedu/address/storage/UserPrefsStorage.java rename to src/main/java/manageezpz/storage/UserPrefsStorage.java index 29eef178dbc..3f0a3bdbc00 100644 --- a/src/main/java/seedu/address/storage/UserPrefsStorage.java +++ b/src/main/java/manageezpz/storage/UserPrefsStorage.java @@ -1,33 +1,35 @@ -package seedu.address.storage; +package manageezpz.storage; import java.io.IOException; import java.nio.file.Path; import java.util.Optional; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyUserPrefs; -import seedu.address.model.UserPrefs; +import manageezpz.commons.exceptions.DataConversionException; +import manageezpz.model.ReadOnlyUserPrefs; +import manageezpz.model.UserPrefs; /** - * Represents a storage for {@link seedu.address.model.UserPrefs}. + * Represents a storage for {@link manageezpz.model.UserPrefs}. */ public interface UserPrefsStorage { /** * Returns the file path of the UserPrefs data file. + * @return Path representation of user preference file path. */ Path getUserPrefsFilePath(); /** * Returns UserPrefs data from storage. - * Returns {@code Optional.empty()} if storage file is not found. + * @return {@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 readUserPrefs() throws DataConversionException, IOException; /** - * Saves the given {@link seedu.address.model.ReadOnlyUserPrefs} to the storage. + * Saves the given {@link manageezpz.model.ReadOnlyUserPrefs} to the storage. * @param userPrefs cannot be null. * @throws IOException if there was any problem writing to the file. */ diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/manageezpz/ui/CommandBox.java similarity index 89% rename from src/main/java/seedu/address/ui/CommandBox.java rename to src/main/java/manageezpz/ui/CommandBox.java index 9e75478664b..39cd5eb50de 100644 --- a/src/main/java/seedu/address/ui/CommandBox.java +++ b/src/main/java/manageezpz/ui/CommandBox.java @@ -1,12 +1,12 @@ -package seedu.address.ui; +package manageezpz.ui; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.TextField; import javafx.scene.layout.Region; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; +import manageezpz.logic.commands.CommandResult; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.logic.parser.exceptions.ParseException; /** * The UI component that is responsible for receiving user command inputs. @@ -77,7 +77,7 @@ public interface CommandExecutor { /** * Executes the command and returns the result. * - * @see seedu.address.logic.Logic#execute(String) + * @see manageezpz.logic.Logic#execute(String) */ CommandResult execute(String commandText) throws CommandException, ParseException; } diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/manageezpz/ui/HelpWindow.java similarity index 66% rename from src/main/java/seedu/address/ui/HelpWindow.java rename to src/main/java/manageezpz/ui/HelpWindow.java index 9a665915949..d1d7e27ce10 100644 --- a/src/main/java/seedu/address/ui/HelpWindow.java +++ b/src/main/java/manageezpz/ui/HelpWindow.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import java.util.logging.Logger; @@ -8,15 +8,20 @@ import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.stage.Stage; -import seedu.address.commons.core.LogsCenter; +import manageezpz.commons.core.LogsCenter; /** * Controller for a help page */ public class HelpWindow extends UiPart { - public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html"; - public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL; + public static final String USERGUIDE_TITLE = "User Guide"; + public static final String USERGUIDE_URL = "https://ay2122s2-cs2103-f11-1.github.io/tp/UserGuide.html"; + + public static final String COPY_CLIPBOARD_FEATURE_TITLE = "About Copying Employee Details to Computer Clipboard"; + public static final String COPY_CLIPBOARD_FEATURE_CONTENT = "ManageEZPZ allows the user to copy an employee's " + + "name, phone number or email to the Computer Clipboard. To copy any of the details, " + + "use the mouse cursor and right-click on the employee in the employees list."; private static final Logger logger = LogsCenter.getLogger(HelpWindow.class); private static final String FXML = "HelpWindow.fxml"; @@ -25,7 +30,16 @@ public class HelpWindow extends UiPart { private Button copyButton; @FXML - private Label helpMessage; + private Label userGuideTitle; + + @FXML + private Label userGuideUrl; + + @FXML + private Label copyClipboardFeatureTitle; + + @FXML + private Label copyClipboardFeatureContent; /** * Creates a new HelpWindow. @@ -34,7 +48,10 @@ public class HelpWindow extends UiPart { */ public HelpWindow(Stage root) { super(FXML, root); - helpMessage.setText(HELP_MESSAGE); + userGuideTitle.setText(USERGUIDE_TITLE); + userGuideUrl.setText(USERGUIDE_URL); + copyClipboardFeatureTitle.setText(COPY_CLIPBOARD_FEATURE_TITLE); + copyClipboardFeatureContent.setText(COPY_CLIPBOARD_FEATURE_CONTENT); } /** diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/manageezpz/ui/MainWindow.java similarity index 89% rename from src/main/java/seedu/address/ui/MainWindow.java rename to src/main/java/manageezpz/ui/MainWindow.java index 9106c3aa6e5..a86b647293e 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/manageezpz/ui/MainWindow.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import java.util.logging.Logger; @@ -10,12 +10,12 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.StackPane; import javafx.stage.Stage; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.core.LogsCenter; -import seedu.address.logic.Logic; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.exceptions.ParseException; +import manageezpz.commons.core.GuiSettings; +import manageezpz.commons.core.LogsCenter; +import manageezpz.logic.Logic; +import manageezpz.logic.commands.CommandResult; +import manageezpz.logic.commands.exceptions.CommandException; +import manageezpz.logic.parser.exceptions.ParseException; /** * The Main Window. Provides the basic application layout containing @@ -32,6 +32,7 @@ public class MainWindow extends UiPart { // Independent Ui parts residing in this Ui container private PersonListPanel personListPanel; + private TaskListPanel taskListPanel; private ResultDisplay resultDisplay; private HelpWindow helpWindow; @@ -44,6 +45,9 @@ public class MainWindow extends UiPart { @FXML private StackPane personListPanelPlaceholder; + @FXML + private StackPane taskListPanelPlaceholder; + @FXML private StackPane resultDisplayPlaceholder; @@ -113,6 +117,9 @@ void fillInnerParts() { personListPanel = new PersonListPanel(logic.getFilteredPersonList()); personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + taskListPanel = new TaskListPanel(logic.getFilteredTaskList()); + taskListPanelPlaceholder.getChildren().add(taskListPanel.getRoot()); + resultDisplay = new ResultDisplay(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); @@ -129,6 +136,7 @@ void fillInnerParts() { private void setWindowDefaultSize(GuiSettings guiSettings) { primaryStage.setHeight(guiSettings.getWindowHeight()); primaryStage.setWidth(guiSettings.getWindowWidth()); + if (guiSettings.getWindowCoordinates() != null) { primaryStage.setX(guiSettings.getWindowCoordinates().getX()); primaryStage.setY(guiSettings.getWindowCoordinates().getY()); @@ -167,10 +175,14 @@ public PersonListPanel getPersonListPanel() { return personListPanel; } + public TaskListPanel getTaskListPanel() { + return taskListPanel; + } + /** * Executes the command and returns the result. * - * @see seedu.address.logic.Logic#execute(String) + * @see manageezpz.logic.Logic#execute(String) */ private CommandResult executeCommand(String commandText) throws CommandException, ParseException { try { diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/manageezpz/ui/PersonCard.java similarity index 80% rename from src/main/java/seedu/address/ui/PersonCard.java rename to src/main/java/manageezpz/ui/PersonCard.java index 7fc927bc5d9..12a2c94d376 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/manageezpz/ui/PersonCard.java @@ -1,13 +1,10 @@ -package seedu.address.ui; - -import java.util.Comparator; +package manageezpz.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.Person; +import manageezpz.model.person.Person; /** * An UI component that displays information of a {@code Person}. @@ -35,11 +32,9 @@ public class PersonCard extends UiPart { @FXML private Label phone; @FXML - private Label address; - @FXML private Label email; @FXML - private FlowPane tags; + private Label numOfTasks; /** * Creates a {@code PersonCode} with the given {@code Person} and index to display. @@ -50,11 +45,8 @@ public PersonCard(Person person, int displayedIndex) { id.setText(displayedIndex + ". "); name.setText(person.getName().fullName); phone.setText(person.getPhone().value); - address.setText(person.getAddress().value); email.setText(person.getEmail().value); - person.getTags().stream() - .sorted(Comparator.comparing(tag -> tag.tagName)) - .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); + numOfTasks.setText(person.getNumOfTasks() + " assigned tasks"); } @Override diff --git a/src/main/java/manageezpz/ui/PersonListPanel.java b/src/main/java/manageezpz/ui/PersonListPanel.java new file mode 100644 index 00000000000..d7dd506d25e --- /dev/null +++ b/src/main/java/manageezpz/ui/PersonListPanel.java @@ -0,0 +1,91 @@ +package manageezpz.ui; + +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.MenuItem; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Region; +import manageezpz.commons.core.LogsCenter; +import manageezpz.model.person.Person; + +/** + * Panel containing the list of persons. + */ +public class PersonListPanel extends UiPart { + + private static final String FXML = "PersonListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); + + @FXML + private ListView personListView; + + /** + * Creates a {@code PersonListPanel} with the given {@code ObservableList}. + */ + public PersonListPanel(ObservableList personList) { + super(FXML); + personListView.setItems(personList); + personListView.setCellFactory(listView -> new PersonListViewCell()); + } + + /** + * Handles the mouse click event when user right-clicks on an employee in the list. + */ + @FXML + public void handleMouseClick(MouseEvent arg) { + final Clipboard clipboard = Clipboard.getSystemClipboard(); + final ClipboardContent content = new ClipboardContent(); + + // Creating a context menu + ContextMenu contextMenu = new ContextMenu(); + + // Creating the menu items for the context menu + MenuItem copyNameItem = new MenuItem("Copy Name"); + MenuItem copyPhoneItem = new MenuItem("Copy Phone Number"); + MenuItem copyEmailItem = new MenuItem("Copy Email"); + contextMenu.getItems().addAll(copyNameItem, copyPhoneItem, copyEmailItem); + + // Adding the context menu to the button and the text field + personListView.setContextMenu(contextMenu); + + copyNameItem.setOnAction((ActionEvent e) -> { + content.putString(personListView.getSelectionModel().getSelectedItem().getName().toString()); + clipboard.setContent(content); + }); + + copyPhoneItem.setOnAction((ActionEvent e) -> { + content.putString(personListView.getSelectionModel().getSelectedItem().getPhone().toString()); + clipboard.setContent(content); + }); + + copyEmailItem.setOnAction((ActionEvent e) -> { + content.putString(personListView.getSelectionModel().getSelectedItem().getEmail().toString()); + clipboard.setContent(content); + }); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. + */ + class PersonListViewCell extends ListCell { + @Override + protected void updateItem(Person person, boolean empty) { + super.updateItem(person, empty); + + if (empty || person == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new PersonCard(person, getIndex() + 1).getRoot()); + } + } + } +} diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/manageezpz/ui/ResultDisplay.java similarity index 68% rename from src/main/java/seedu/address/ui/ResultDisplay.java rename to src/main/java/manageezpz/ui/ResultDisplay.java index 7d98e84eedf..6c2892e976a 100644 --- a/src/main/java/seedu/address/ui/ResultDisplay.java +++ b/src/main/java/manageezpz/ui/ResultDisplay.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import static java.util.Objects.requireNonNull; @@ -12,17 +12,22 @@ public class ResultDisplay extends UiPart { private static final String FXML = "ResultDisplay.fxml"; + private static final String WELCOME_MESSAGE = "Welcome to ManageEZPZ!"; @FXML private TextArea resultDisplay; + /** + * Initializes a {@code ResultDisplay} and sets the welcome message on + * {@code TextArea} resultDisplay. + */ public ResultDisplay() { super(FXML); + resultDisplay.setText(WELCOME_MESSAGE); } public void setFeedbackToUser(String feedbackToUser) { requireNonNull(feedbackToUser); resultDisplay.setText(feedbackToUser); } - } diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/manageezpz/ui/StatusBarFooter.java similarity index 96% rename from src/main/java/seedu/address/ui/StatusBarFooter.java rename to src/main/java/manageezpz/ui/StatusBarFooter.java index b577f829423..95f3b75bbf1 100644 --- a/src/main/java/seedu/address/ui/StatusBarFooter.java +++ b/src/main/java/manageezpz/ui/StatusBarFooter.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/src/main/java/manageezpz/ui/TaskCard.java b/src/main/java/manageezpz/ui/TaskCard.java new file mode 100644 index 00000000000..00d39b4879b --- /dev/null +++ b/src/main/java/manageezpz/ui/TaskCard.java @@ -0,0 +1,221 @@ +package manageezpz.ui; + +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import manageezpz.model.task.Deadline; +import manageezpz.model.task.Event; +import manageezpz.model.task.Task; +import manageezpz.model.task.Todo; + +/** + * An UI component that displays information of a {@code Task}. + */ +public class TaskCard extends UiPart { + + private static final String FXML = "TaskListCard.fxml"; + + /** + * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. + * As a consequence, UI elements' variable names cannot be set to such keywords + * or an exception will be thrown by JavaFX during runtime. + * + * @see The issue on AddressBook level 4 + */ + + public final Task task; + + @FXML + private HBox cardPane; + @FXML + private GridPane detailsPane; + @FXML + private Label id; + @FXML + private Label description; + @FXML + private Label type; + @FXML + private Label dateTimeLabel; + @FXML + private Label dateTime; + @FXML + private Label employeesTagLabel; + @FXML + private Label employeesTag; + @FXML + private Label priorityTagLabel; + @FXML + private ImageView priorityTagIcon; + @FXML + private Label priorityTag; + @FXML + private Label statusIsDoneLabel; + @FXML + private Label statusIsDone; + + /** + * Creates a {@code TaskCard} with the given {@code Task} and index to display. + */ + public TaskCard(Task task, int displayedIndex) { + super(FXML); + this.task = task; + + id.setText(displayedIndex + ". "); + description.setText(task.getDescription().description); + type.setText(task.getType()); + + if (task instanceof Deadline || task instanceof Event) { + dateTime.setText(task.getDateTime()); + } + + setEmployeeTag(); + setPriorityTagIconAndPriorityTag(); + setStatusIsDone(); + removeEmptyRows(); + } + + /** + * Sets the text of employeesTag {@code Label}. + */ + private void setEmployeeTag() { + if (!task.getAssignees().isEmpty()) { + String assigneesNames = task.getAssignees() + .stream() + .flatMap(person -> Stream.of(person.getName().fullName)) + .collect(Collectors.joining(", ")); + + employeesTag.setText(assigneesNames); + } + } + + /** + * Sets the image of priorityTagIcon {@code ImageView} and the text of priorityTag {@code Label}. + */ + private void setPriorityTagIconAndPriorityTag() { + Image priorityIcon; + + switch (task.getPriority().name()) { + case "LOW": + priorityIcon = new Image(Objects.requireNonNull( + getClass().getResourceAsStream("/images/priorities_low.png"))); + priorityTagIcon.setImage(priorityIcon); + priorityTag.setText(task.getPriority().name()); + break; + case "MEDIUM": + priorityIcon = new Image(Objects.requireNonNull( + getClass().getResourceAsStream("/images/priorities_medium.png"))); + priorityTagIcon.setImage(priorityIcon); + priorityTag.setText(task.getPriority().name()); + break; + case "HIGH": + priorityIcon = new Image(Objects.requireNonNull( + getClass().getResourceAsStream("/images/priorities_high.png"))); + priorityTagIcon.setImage(priorityIcon); + priorityTag.setText(task.getPriority().name()); + break; + case "NONE": + break; + default: + throw new RuntimeException("Invalid Task Priority"); + } + } + + /** + * Sets the text of statusIsDone {@code Label}. + */ + private void setStatusIsDone() { + if (task.isDone()) { + statusIsDone.setText("Done"); + statusIsDone.getStyleClass().add("cell_completion_done_label"); + } else { + statusIsDone.setText("Not Done"); + statusIsDone.getStyleClass().add("cell_completion_not_done_label"); + } + } + + /** + * Removes empty rows from the detailsPane {@code GridPane}. + */ + private void removeEmptyRows() { + // Remove date/time row if it is a Todo task + if (task instanceof Todo) { + removeRow(detailsPane, GridPane.getRowIndex(dateTimeLabel)); + } + + // Remove assignees row if there are no employees assigned to the task + if (task.getAssignees().isEmpty()) { + removeRow(detailsPane, GridPane.getRowIndex(employeesTagLabel)); + } + + // Remove priority row if there are no priority tagged to the task + if (task.getPriority().name().equals("NONE")) { + removeRow(detailsPane, GridPane.getRowIndex(priorityTagLabel)); + } + } + + /** + * Gets row index constrain for given node, forcefully as integer: 0 as null. + * + * @param node Node to look up the constraint for + * @return The row index as primitive integer + */ + private int getRowIndexAsInteger(Node node) { + return GridPane.getRowIndex(node) == null ? 0 : GridPane.getRowIndex(node); + } + + /** + * Removes row from grid pane by index. + * Adapted from https://stackoverflow.com/a/70961583. + * + * @param grid Grid pane to be affected + * @param targetRowIndexIntegerObject Target row index to be removed. Integer object type, + * because for some reason `getRowIndex` returns null + * for children at 0th row. + */ + private void removeRow(GridPane grid, Integer targetRowIndexIntegerObject) { + int targetRowIndex = targetRowIndexIntegerObject == null ? 0 : targetRowIndexIntegerObject; + + // Remove children from row + grid.getChildren().removeIf(node -> (getRowIndexAsInteger(node) == targetRowIndex)); + + // Update indexes of other rows, i.e., shift rows up + grid.getChildren().forEach(node -> { + int rowIndex = getRowIndexAsInteger(node); + + if (targetRowIndex < rowIndex) { + GridPane.setRowIndex(node, rowIndex - 1); + } + }); + + // Remove row constraints + grid.getRowConstraints().remove(targetRowIndex); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof TaskCard)) { + return false; + } + + // state check + TaskCard card = (TaskCard) other; + return id.getText().equals(card.id.getText()) + && task.equals(card.task); + } +} diff --git a/src/main/java/manageezpz/ui/TaskListPanel.java b/src/main/java/manageezpz/ui/TaskListPanel.java new file mode 100644 index 00000000000..fd5f21c335d --- /dev/null +++ b/src/main/java/manageezpz/ui/TaskListPanel.java @@ -0,0 +1,49 @@ +package manageezpz.ui; + +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.layout.Region; +import manageezpz.commons.core.LogsCenter; +import manageezpz.model.task.Task; + +/** + * Panel containing the list of tasks. + */ +public class TaskListPanel extends UiPart { + + private static final String FXML = "TaskListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(TaskListPanel.class); + + @FXML + private ListView taskListView; + + /** + * Creates a {@code TaskListPanel} with the given {@code ObservableList}. + */ + public TaskListPanel(ObservableList taskList) { + super(FXML); + taskListView.setItems(taskList); + taskListView.setCellFactory(listView -> new TaskListViewCell()); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Task} using a {@code TaskCard}. + */ + class TaskListViewCell extends ListCell { + @Override + protected void updateItem(Task task, boolean empty) { + super.updateItem(task, empty); + + if (empty || task == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new TaskCard(task, getIndex() + 1).getRoot()); + } + } + } +} diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/manageezpz/ui/Ui.java similarity index 86% rename from src/main/java/seedu/address/ui/Ui.java rename to src/main/java/manageezpz/ui/Ui.java index 17aa0b494fe..470fb97337e 100644 --- a/src/main/java/seedu/address/ui/Ui.java +++ b/src/main/java/manageezpz/ui/Ui.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import javafx.stage.Stage; diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/manageezpz/ui/UiManager.java similarity index 88% rename from src/main/java/seedu/address/ui/UiManager.java rename to src/main/java/manageezpz/ui/UiManager.java index fdf024138bc..4ba91c56f61 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/manageezpz/ui/UiManager.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import java.util.logging.Logger; @@ -7,10 +7,10 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.image.Image; import javafx.stage.Stage; -import seedu.address.MainApp; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; +import manageezpz.MainApp; +import manageezpz.commons.core.LogsCenter; +import manageezpz.commons.util.StringUtil; +import manageezpz.logic.Logic; /** * The manager of the UI component. @@ -20,7 +20,7 @@ public class UiManager implements Ui { public static final String ALERT_DIALOG_PANE_FIELD_ID = "alertDialogPane"; private static final Logger logger = LogsCenter.getLogger(UiManager.class); - private static final String ICON_APPLICATION = "/images/address_book_32.png"; + private static final String ICON_APPLICATION = "/images/task_icon.png"; private Logic logic; private MainWindow mainWindow; @@ -41,9 +41,8 @@ public void start(Stage primaryStage) { try { mainWindow = new MainWindow(primaryStage, logic); - mainWindow.show(); //This should be called before creating other UI parts + mainWindow.show(); // This should be called before creating other UI parts mainWindow.fillInnerParts(); - } catch (Throwable e) { logger.severe(StringUtil.getDetails(e)); showFatalErrorDialogAndShutdown("Fatal error during initializing", e); diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/manageezpz/ui/UiPart.java similarity index 96% rename from src/main/java/seedu/address/ui/UiPart.java rename to src/main/java/manageezpz/ui/UiPart.java index fc820e01a9c..da9e03f6ea9 100644 --- a/src/main/java/seedu/address/ui/UiPart.java +++ b/src/main/java/manageezpz/ui/UiPart.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package manageezpz.ui; import static java.util.Objects.requireNonNull; @@ -6,7 +6,7 @@ import java.net.URL; import javafx.fxml.FXMLLoader; -import seedu.address.MainApp; +import manageezpz.MainApp; /** * Represents a distinct part of the UI. e.g. Windows, dialogs, panels, status bars, etc. @@ -45,7 +45,7 @@ public UiPart(URL fxmlFileUrl, T root) { /** * Constructs a UiPart with the specified FXML file within {@link #FXML_FILE_FOLDER} and root object. - * @see #UiPart(URL, T) + * @see #UiPart(URL, Object) */ public UiPart(String fxmlFileName, T root) { this(getFxmlFileUrl(fxmlFileName), root); 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 1deb3a1e469..00000000000 --- 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/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java deleted file mode 100644 index 71656d7c5c8..00000000000 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ /dev/null @@ -1,67 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; -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_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; - -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; -import seedu.address.model.person.Person; - -/** - * 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: " - + PREFIX_NAME + "NAME " - + PREFIX_PHONE + "PHONE " - + PREFIX_EMAIL + "EMAIL " - + PREFIX_ADDRESS + "ADDRESS " - + "[" + PREFIX_TAG + "TAG]...\n" - + "Example: " + COMMAND_WORD + " " - + PREFIX_NAME + "John Doe " - + PREFIX_PHONE + "98765432 " - + PREFIX_EMAIL + "johnd@example.com " - + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " - + PREFIX_TAG + "friends " - + PREFIX_TAG + "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 to add the specified {@code Person} - */ - public AddCommand(Person person) { - requireNonNull(person); - toAdd = person; - } - - @Override - public CommandResult execute(Model model) throws CommandException { - requireNonNull(model); - - if (model.hasPerson(toAdd)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); - } - - model.addPerson(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof AddCommand // instanceof handles nulls - && toAdd.equals(((AddCommand) other).toAdd)); - } -} 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 02fd256acba..00000000000 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; - -import java.util.List; - -import seedu.address.commons.core.Messages; -import seedu.address.commons.core.index.Index; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; -import seedu.address.model.person.Person; - -/** - * Deletes a person identified using it's 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 displayed person list.\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"; - - private final Index targetIndex; - - public DeleteCommand(Index targetIndex) { - this.targetIndex = targetIndex; - } - - @Override - public CommandResult execute(Model model) throws CommandException { - requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); - - if (targetIndex.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - Person personToDelete = lastShownList.get(targetIndex.getZeroBased()); - model.deletePerson(personToDelete); - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof DeleteCommand // instanceof handles nulls - && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check - } -} 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 7e36114902f..00000000000 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ /dev/null @@ -1,226 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; -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_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import seedu.address.commons.core.Messages; -import seedu.address.commons.core.index.Index; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; -import seedu.address.model.person.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.tag.Tag; - -/** - * 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 displayed person list. " - + "Existing values will be overwritten by the input values.\n" - + "Parameters: INDEX (must be a positive integer) " - + "[" + PREFIX_NAME + "NAME] " - + "[" + PREFIX_PHONE + "PHONE] " - + "[" + PREFIX_EMAIL + "EMAIL] " - + "[" + PREFIX_ADDRESS + "ADDRESS] " - + "[" + PREFIX_TAG + "TAG]...\n" - + "Example: " + COMMAND_WORD + " 1 " - + PREFIX_PHONE + "91234567 " - + PREFIX_EMAIL + "johndoe@example.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 Index index; - private final EditPersonDescriptor editPersonDescriptor; - - /** - * @param index of the person in the filtered person list to edit - * @param editPersonDescriptor details to edit the person with - */ - public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) { - requireNonNull(index); - requireNonNull(editPersonDescriptor); - - this.index = index; - this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor); - } - - @Override - public CommandResult execute(Model model) throws CommandException { - requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); - - if (index.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); - - if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); - } - - model.setPerson(personToEdit, editedPerson); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); - } - - /** - * Creates and returns a {@code Person} with the details of {@code personToEdit} - * edited with {@code editPersonDescriptor}. - */ - private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) { - assert personToEdit != null; - - Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName()); - Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); - Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); - Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); - Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); - - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); - } - - @Override - public boolean equals(Object other) { - // short circuit if same object - if (other == this) { - return true; - } - - // instanceof handles nulls - if (!(other instanceof EditCommand)) { - return false; - } - - // state check - EditCommand e = (EditCommand) other; - return index.equals(e.index) - && editPersonDescriptor.equals(e.editPersonDescriptor); - } - - /** - * 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 Name name; - private Phone phone; - private Email email; - private Address address; - private Set tags; - - public EditPersonDescriptor() {} - - /** - * Copy constructor. - * A defensive copy of {@code tags} is used internally. - */ - public EditPersonDescriptor(EditPersonDescriptor toCopy) { - setName(toCopy.name); - setPhone(toCopy.phone); - setEmail(toCopy.email); - setAddress(toCopy.address); - setTags(toCopy.tags); - } - - /** - * Returns true if at least one field is edited. - */ - public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); - } - - public void setName(Name name) { - this.name = name; - } - - public Optional getName() { - return Optional.ofNullable(name); - } - - public void setPhone(Phone phone) { - this.phone = phone; - } - - public Optional getPhone() { - return Optional.ofNullable(phone); - } - - public void setEmail(Email email) { - this.email = email; - } - - public Optional getEmail() { - return Optional.ofNullable(email); - } - - public void setAddress(Address address) { - this.address = address; - } - - public Optional
getAddress() { - return Optional.ofNullable(address); - } - - /** - * Sets {@code tags} to this object's {@code tags}. - * A defensive copy of {@code tags} is used internally. - */ - public void setTags(Set tags) { - this.tags = (tags != null) ? new HashSet<>(tags) : null; - } - - /** - * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} - * if modification is attempted. - * Returns {@code Optional#empty()} if {@code tags} is null. - */ - public Optional> getTags() { - return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); - } - - @Override - public boolean equals(Object other) { - // short circuit if same object - if (other == this) { - return true; - } - - // instanceof handles nulls - if (!(other instanceof EditPersonDescriptor)) { - return false; - } - - // state check - EditPersonDescriptor e = (EditPersonDescriptor) other; - - return getName().equals(e.getName()) - && getPhone().equals(e.getPhone()) - && getEmail().equals(e.getEmail()) - && getAddress().equals(e.getAddress()) - && getTags().equals(e.getTags()); - } - } -} diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java deleted file mode 100644 index d6b19b0a0de..00000000000 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; - -import seedu.address.commons.core.Messages; -import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; - -/** - * Finds and lists all persons in address book whose name contains any of the argument keywords. - * Keyword matching is case insensitive. - */ -public class FindCommand extends Command { - - public static final String COMMAND_WORD = "find"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of " - + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; - - private final NameContainsKeywordsPredicate predicate; - - public FindCommand(NameContainsKeywordsPredicate predicate) { - this.predicate = predicate; - } - - @Override - public CommandResult execute(Model model) { - requireNonNull(model); - model.updateFilteredPersonList(predicate); - return new CommandResult( - String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size())); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof FindCommand // instanceof handles nulls - && predicate.equals(((FindCommand) other).predicate)); // state check - } -} diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java deleted file mode 100644 index bf824f91bd0..00000000000 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ /dev/null @@ -1,21 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.model.Model; - -/** - * Format full help instructions for every command for display. - */ -public class HelpCommand extends Command { - - public static final String COMMAND_WORD = "help"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" - + "Example: " + COMMAND_WORD; - - public static final String SHOWING_HELP_MESSAGE = "Opened help window."; - - @Override - public CommandResult execute(Model model) { - return new CommandResult(SHOWING_HELP_MESSAGE, true, false); - } -} diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java deleted file mode 100644 index 84be6ad2596..00000000000 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package seedu.address.logic.commands; - -import static java.util.Objects.requireNonNull; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; - -import seedu.address.model.Model; - -/** - * Lists all persons in the address book to the user. - */ -public class ListCommand extends Command { - - public static final String COMMAND_WORD = "list"; - - public static final String MESSAGE_SUCCESS = "Listed all persons"; - - - @Override - public CommandResult execute(Model model) { - requireNonNull(model); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(MESSAGE_SUCCESS); - } -} 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 3b8bfa035e8..00000000000 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ /dev/null @@ -1,60 +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_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; - -import java.util.Set; -import java.util.stream.Stream; - -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.parser.exceptions.ParseException; -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.tag.Tag; - -/** - * Parses input arguments and creates a new AddCommand object - */ -public class AddCommandParser implements Parser { - - /** - * Parses the given {@code String} of arguments in the context of the AddCommand - * and returns an AddCommand object for execution. - * @throws ParseException if the user input does not conform the expected format - */ - public AddCommand parse(String args) throws ParseException { - ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); - - if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL) - || !argMultimap.getPreamble().isEmpty()) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); - } - - Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); - Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); - Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); - Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()); - Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); - - Person person = new Person(name, phone, email, address, tagList); - - return new AddCommand(person); - } - - /** - * Returns true if none of the prefixes contains empty {@code Optional} values in the given - * {@code ArgumentMultimap}. - */ - private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { - return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); - } - -} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java deleted file mode 100644 index 1e466792b46..00000000000 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ /dev/null @@ -1,76 +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.ListCommand; -import seedu.address.logic.parser.exceptions.ParseException; - -/** - * Parses user input. - */ -public class AddressBookParser { - - /** - * 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 - * @throws ParseException if the user input does not conform the expected format - */ - public Command parseCommand(String userInput) throws ParseException { - final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); - if (!matcher.matches()) { - throw new ParseException(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 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: - throw new ParseException(MESSAGE_UNKNOWN_COMMAND); - } - } - -} diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java deleted file mode 100644 index 75b1a9bf119..00000000000 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ /dev/null @@ -1,15 +0,0 @@ -package seedu.address.logic.parser; - -/** - * Contains Command Line Interface (CLI) syntax definitions common to multiple commands - */ -public class CliSyntax { - - /* Prefix definitions */ - public static final Prefix PREFIX_NAME = new Prefix("n/"); - 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_TAG = new Prefix("t/"); - -} diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java deleted file mode 100644 index 522b93081cc..00000000000 --- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java +++ /dev/null @@ -1,29 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; - -import seedu.address.commons.core.index.Index; -import seedu.address.logic.commands.DeleteCommand; -import seedu.address.logic.parser.exceptions.ParseException; - -/** - * Parses input arguments and creates a new DeleteCommand object - */ -public class DeleteCommandParser implements Parser { - - /** - * Parses the given {@code String} of arguments in the context of the DeleteCommand - * and returns a DeleteCommand object for execution. - * @throws ParseException if the user input does not conform the expected format - */ - public DeleteCommand parse(String args) throws ParseException { - try { - Index index = ParserUtil.parseIndex(args); - return new DeleteCommand(index); - } catch (ParseException pe) { - throw new ParseException( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe); - } - } - -} 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 845644b7dea..00000000000 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ /dev/null @@ -1,82 +0,0 @@ -package seedu.address.logic.parser; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -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.Optional; -import java.util.Set; - -import seedu.address.commons.core.index.Index; -import seedu.address.logic.commands.EditCommand; -import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.tag.Tag; - -/** - * Parses input arguments and creates a new EditCommand object - */ -public class EditCommandParser implements Parser { - - /** - * Parses the given {@code String} of arguments in the context of the EditCommand - * and returns an EditCommand object for execution. - * @throws ParseException if the user input does not conform the expected format - */ - public EditCommand parse(String args) throws ParseException { - requireNonNull(args); - ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); - - Index index; - - try { - index = ParserUtil.parseIndex(argMultimap.getPreamble()); - } catch (ParseException pe) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); - } - - EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor(); - if (argMultimap.getValue(PREFIX_NAME).isPresent()) { - editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get())); - } - if (argMultimap.getValue(PREFIX_PHONE).isPresent()) { - editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get())); - } - if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { - editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); - } - if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { - editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); - } - parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); - - if (!editPersonDescriptor.isAnyFieldEdited()) { - throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); - } - - return new EditCommand(index, editPersonDescriptor); - } - - /** - * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty. - * If {@code tags} contain only one element which is an empty string, it will be parsed into a - * {@code Set} containing zero tags. - */ - private Optional> parseTagsForEdit(Collection tags) throws ParseException { - assert tags != null; - - if (tags.isEmpty()) { - return Optional.empty(); - } - Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags; - return Optional.of(ParserUtil.parseTags(tagSet)); - } - -} diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java deleted file mode 100644 index 4fb71f23103..00000000000 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ /dev/null @@ -1,33 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; - -import java.util.Arrays; - -import seedu.address.logic.commands.FindCommand; -import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; - -/** - * Parses input arguments and creates a new FindCommand object - */ -public class FindCommandParser implements Parser { - - /** - * Parses the given {@code String} of arguments in the context of the FindCommand - * and returns a FindCommand object for execution. - * @throws ParseException if the user input does not conform the expected format - */ - public FindCommand parse(String args) throws ParseException { - String trimmedArgs = args.trim(); - if (trimmedArgs.isEmpty()) { - throw new ParseException( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); - } - - String[] nameKeywords = trimmedArgs.split("\\s+"); - - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); - } - -} 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 1a943a0781a..00000000000 --- a/src/main/java/seedu/address/model/AddressBook.java +++ /dev/null @@ -1,120 +0,0 @@ -package seedu.address.model; - -import static java.util.Objects.requireNonNull; - -import java.util.List; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.UniquePersonList; - -/** - * Wraps all data at the address-book level - * Duplicates are not allowed (by .isSamePerson comparison) - */ -public class AddressBook implements ReadOnlyAddressBook { - - private final UniquePersonList persons; - - /* - * The 'unusual' code block below is a 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(); - } - - public AddressBook() {} - - /** - * Creates an AddressBook using the Persons in the {@code toBeCopied} - */ - public AddressBook(ReadOnlyAddressBook toBeCopied) { - this(); - resetData(toBeCopied); - } - - //// list overwrite operations - - /** - * Replaces the contents of the person list with {@code persons}. - * {@code persons} must not contain duplicate persons. - */ - public void setPersons(List persons) { - this.persons.setPersons(persons); - } - - /** - * Resets the existing data of this {@code AddressBook} with {@code newData}. - */ - public void resetData(ReadOnlyAddressBook newData) { - requireNonNull(newData); - - setPersons(newData.getPersonList()); - } - - //// person-level operations - - /** - * Returns true if a person with the same identity as {@code person} exists in the address book. - */ - public boolean hasPerson(Person person) { - requireNonNull(person); - return persons.contains(person); - } - - /** - * Adds a person to the address book. - * The person must not already exist in the address book. - */ - public void addPerson(Person p) { - persons.add(p); - } - - /** - * Replaces the given person {@code target} in the list with {@code editedPerson}. - * {@code target} must exist in the address book. - * The person identity of {@code editedPerson} must not be the same as another existing person in the address book. - */ - public void setPerson(Person target, Person editedPerson) { - requireNonNull(editedPerson); - - persons.setPerson(target, editedPerson); - } - - /** - * Removes {@code key} from this {@code AddressBook}. - * {@code key} must exist in the address book. - */ - public void removePerson(Person key) { - persons.remove(key); - } - - //// util methods - - @Override - public String toString() { - return persons.asUnmodifiableObservableList().size() + " persons"; - // TODO: refine later - } - - @Override - public ObservableList getPersonList() { - return persons.asUnmodifiableObservableList(); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof AddressBook // instanceof handles nulls - && persons.equals(((AddressBook) other).persons)); - } - - @Override - public int hashCode() { - return persons.hashCode(); - } -} 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 d54df471c1f..00000000000 --- a/src/main/java/seedu/address/model/Model.java +++ /dev/null @@ -1,87 +0,0 @@ -package seedu.address.model; - -import java.nio.file.Path; -import java.util.function.Predicate; - -import javafx.collections.ObservableList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.model.person.Person; - -/** - * The API of the Model component. - */ -public interface Model { - /** {@code Predicate} that always evaluate to true */ - Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true; - - /** - * Replaces user prefs data with the data in {@code userPrefs}. - */ - void setUserPrefs(ReadOnlyUserPrefs userPrefs); - - /** - * Returns the user prefs. - */ - ReadOnlyUserPrefs getUserPrefs(); - - /** - * Returns the user prefs' GUI settings. - */ - GuiSettings getGuiSettings(); - - /** - * Sets the user prefs' GUI settings. - */ - void setGuiSettings(GuiSettings guiSettings); - - /** - * Returns the user prefs' address book file path. - */ - Path getAddressBookFilePath(); - - /** - * Sets the user prefs' address book file path. - */ - void setAddressBookFilePath(Path addressBookFilePath); - - /** - * Replaces address book data with the data in {@code addressBook}. - */ - void setAddressBook(ReadOnlyAddressBook addressBook); - - /** Returns the AddressBook */ - ReadOnlyAddressBook getAddressBook(); - - /** - * Returns true if a person with the same identity as {@code person} exists in the address book. - */ - boolean hasPerson(Person person); - - /** - * Deletes the given person. - * The person must exist in the address book. - */ - void deletePerson(Person target); - - /** - * Adds the given person. - * {@code person} must not already exist in the address book. - */ - void addPerson(Person person); - - /** - * Replaces the given person {@code target} with {@code editedPerson}. - * {@code target} must exist in the address book. - * The person identity of {@code editedPerson} must not be the same as another existing person in the address book. - */ - void setPerson(Person target, Person editedPerson); - - /** Returns an unmodifiable view of the filtered person list */ - ObservableList getFilteredPersonList(); - - /** - * Updates the filter of the filtered person list to filter by the given {@code predicate}. - * @throws NullPointerException if {@code predicate} is null. - */ - void updateFilteredPersonList(Predicate predicate); -} 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 86c1df298d7..00000000000 --- a/src/main/java/seedu/address/model/ModelManager.java +++ /dev/null @@ -1,150 +0,0 @@ -package seedu.address.model; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; - -import java.nio.file.Path; -import java.util.function.Predicate; -import java.util.logging.Logger; - -import javafx.collections.ObservableList; -import javafx.collections.transformation.FilteredList; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; - -/** - * Represents the in-memory model of the address book data. - */ -public class ModelManager implements Model { - private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - - private final AddressBook addressBook; - private final UserPrefs userPrefs; - private final FilteredList filteredPersons; - - /** - * Initializes a ModelManager with the given addressBook and userPrefs. - */ - public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) { - requireAllNonNull(addressBook, userPrefs); - - logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs); - - this.addressBook = new AddressBook(addressBook); - this.userPrefs = new UserPrefs(userPrefs); - filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); - } - - public ModelManager() { - this(new AddressBook(), new UserPrefs()); - } - - //=========== UserPrefs ================================================================================== - - @Override - public void setUserPrefs(ReadOnlyUserPrefs userPrefs) { - requireNonNull(userPrefs); - this.userPrefs.resetData(userPrefs); - } - - @Override - public ReadOnlyUserPrefs getUserPrefs() { - return userPrefs; - } - - @Override - public GuiSettings getGuiSettings() { - return userPrefs.getGuiSettings(); - } - - @Override - public void setGuiSettings(GuiSettings guiSettings) { - requireNonNull(guiSettings); - userPrefs.setGuiSettings(guiSettings); - } - - @Override - public Path getAddressBookFilePath() { - return userPrefs.getAddressBookFilePath(); - } - - @Override - public void setAddressBookFilePath(Path addressBookFilePath) { - requireNonNull(addressBookFilePath); - userPrefs.setAddressBookFilePath(addressBookFilePath); - } - - //=========== AddressBook ================================================================================ - - @Override - public void setAddressBook(ReadOnlyAddressBook addressBook) { - this.addressBook.resetData(addressBook); - } - - @Override - public ReadOnlyAddressBook getAddressBook() { - return addressBook; - } - - @Override - public boolean hasPerson(Person person) { - requireNonNull(person); - return addressBook.hasPerson(person); - } - - @Override - public void deletePerson(Person target) { - addressBook.removePerson(target); - } - - @Override - public void addPerson(Person person) { - addressBook.addPerson(person); - updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - } - - @Override - public void setPerson(Person target, Person editedPerson) { - requireAllNonNull(target, editedPerson); - - addressBook.setPerson(target, editedPerson); - } - - //=========== Filtered Person List Accessors ============================================================= - - /** - * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of - * {@code versionedAddressBook} - */ - @Override - public ObservableList getFilteredPersonList() { - return filteredPersons; - } - - @Override - public void updateFilteredPersonList(Predicate predicate) { - requireNonNull(predicate); - filteredPersons.setPredicate(predicate); - } - - @Override - public boolean equals(Object obj) { - // short circuit if same object - if (obj == this) { - return true; - } - - // instanceof handles nulls - if (!(obj instanceof ModelManager)) { - return false; - } - - // state check - ModelManager other = (ModelManager) obj; - return addressBook.equals(other.addressBook) - && userPrefs.equals(other.userPrefs) - && filteredPersons.equals(other.filteredPersons); - } - -} 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 6ddc2cd9a29..00000000000 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ /dev/null @@ -1,17 +0,0 @@ -package seedu.address.model; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; - -/** - * 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(); - -} 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 60472ca22a0..00000000000 --- a/src/main/java/seedu/address/model/person/Address.java +++ /dev/null @@ -1,57 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * 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_CONSTRAINTS = "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 VALIDATION_REGEX = "[^\\s].*"; - - public final String value; - - /** - * Constructs an {@code Address}. - * - * @param address A valid address. - */ - public Address(String address) { - requireNonNull(address); - checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); - value = address; - } - - /** - * Returns true if a given string is a valid email. - */ - public static boolean isValidAddress(String test) { - return test.matches(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 - && value.equals(((Address) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java deleted file mode 100644 index c9b5868427c..00000000000 --- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java +++ /dev/null @@ -1,31 +0,0 @@ -package seedu.address.model.person; - -import java.util.List; -import java.util.function.Predicate; - -import seedu.address.commons.util.StringUtil; - -/** - * Tests that a {@code Person}'s {@code Name} matches any of the keywords given. - */ -public class NameContainsKeywordsPredicate implements Predicate { - private final List keywords; - - public NameContainsKeywordsPredicate(List keywords) { - this.keywords = keywords; - } - - @Override - public boolean test(Person person) { - return keywords.stream() - .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls - && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check - } - -} 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 1806da4facf..00000000000 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.model.util; - -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - -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.tag.Tag; - -/** - * Contains utility methods for populating {@code AddressBook} with sample data. - */ -public class SampleDataUtil { - public static Person[] getSamplePersons() { - return new Person[] { - new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), - new Address("Blk 30 Geylang Street 29, #06-40"), - getTagSet("friends")), - new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), - new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), - getTagSet("colleagues", "friends")), - new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), - new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), - getTagSet("neighbours")), - new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), - new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), - getTagSet("family")), - new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), - new Address("Blk 47 Tampines Street 20, #17-35"), - getTagSet("classmates")), - new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), - new Address("Blk 45 Aljunied Street 85, #11-31"), - getTagSet("colleagues")) - }; - } - - public static ReadOnlyAddressBook getSampleAddressBook() { - AddressBook sampleAb = new AddressBook(); - for (Person samplePerson : getSamplePersons()) { - sampleAb.addPerson(samplePerson); - } - return sampleAb; - } - - /** - * Returns a tag set containing the list of strings given. - */ - public static Set getTagSet(String... strings) { - return Arrays.stream(strings) - .map(Tag::new) - .collect(Collectors.toSet()); - } - -} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java deleted file mode 100644 index 0df22bdb754..00000000000 --- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java +++ /dev/null @@ -1,48 +0,0 @@ -package seedu.address.storage; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; - -/** - * Jackson-friendly version of {@link Tag}. - */ -class JsonAdaptedTag { - - private final String tagName; - - /** - * Constructs a {@code JsonAdaptedTag} with the given {@code tagName}. - */ - @JsonCreator - public JsonAdaptedTag(String tagName) { - this.tagName = tagName; - } - - /** - * Converts a given {@code Tag} into this class for Jackson use. - */ - public JsonAdaptedTag(Tag source) { - tagName = source.tagName; - } - - @JsonValue - public String getTagName() { - return tagName; - } - - /** - * Converts this Jackson-friendly adapted tag object into the model's {@code Tag} object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted tag. - */ - public Tag toModelType() throws IllegalValueException { - if (!Tag.isValidTagName(tagName)) { - throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS); - } - return new Tag(tagName); - } - -} diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java deleted file mode 100644 index 5efd834091d..00000000000 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.storage; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonRootName; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; - -/** - * An Immutable AddressBook that is serializable to JSON format. - */ -@JsonRootName(value = "addressbook") -class JsonSerializableAddressBook { - - public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; - - private final List persons = new ArrayList<>(); - - /** - * Constructs a {@code JsonSerializableAddressBook} with the given persons. - */ - @JsonCreator - public JsonSerializableAddressBook(@JsonProperty("persons") List persons) { - this.persons.addAll(persons); - } - - /** - * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use. - * - * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}. - */ - public JsonSerializableAddressBook(ReadOnlyAddressBook source) { - persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList())); - } - - /** - * Converts this address book into the model's {@code AddressBook} object. - * - * @throws IllegalValueException if there were any data constraints violated. - */ - public AddressBook toModelType() throws IllegalValueException { - AddressBook addressBook = new AddressBook(); - for (JsonAdaptedPerson jsonAdaptedPerson : persons) { - Person person = jsonAdaptedPerson.toModelType(); - if (addressBook.hasPerson(person)) { - throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON); - } - addressBook.addPerson(person); - } - return addressBook; - } - -} diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java deleted file mode 100644 index f4c501a897b..00000000000 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ /dev/null @@ -1,49 +0,0 @@ -package seedu.address.ui; - -import java.util.logging.Logger; - -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.layout.Region; -import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; - -/** - * Panel containing the list of persons. - */ -public class PersonListPanel extends UiPart { - private static final String FXML = "PersonListPanel.fxml"; - private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); - - @FXML - private ListView personListView; - - /** - * Creates a {@code PersonListPanel} with the given {@code ObservableList}. - */ - public PersonListPanel(ObservableList personList) { - super(FXML); - personListView.setItems(personList); - personListView.setCellFactory(listView -> new PersonListViewCell()); - } - - /** - * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. - */ - class PersonListViewCell extends ListCell { - @Override - protected void updateItem(Person person, boolean empty) { - super.updateItem(person, empty); - - if (empty || person == null) { - setGraphic(null); - setText(null); - } else { - setGraphic(new PersonCard(person, getIndex() + 1).getRoot()); - } - } - } - -} diff --git a/src/main/resources/images/email_icon.png b/src/main/resources/images/email_icon.png new file mode 100644 index 00000000000..fbcc54c9b44 Binary files /dev/null and b/src/main/resources/images/email_icon.png differ diff --git a/src/main/resources/images/employee_icon.png b/src/main/resources/images/employee_icon.png new file mode 100644 index 00000000000..c109dd85302 Binary files /dev/null and b/src/main/resources/images/employee_icon.png differ diff --git a/src/main/resources/images/phone_icon.png b/src/main/resources/images/phone_icon.png new file mode 100644 index 00000000000..cf419e7a195 Binary files /dev/null and b/src/main/resources/images/phone_icon.png differ diff --git a/src/main/resources/images/priorities_high.png b/src/main/resources/images/priorities_high.png new file mode 100644 index 00000000000..25f6325cfcd Binary files /dev/null and b/src/main/resources/images/priorities_high.png differ diff --git a/src/main/resources/images/priorities_low.png b/src/main/resources/images/priorities_low.png new file mode 100644 index 00000000000..ef947e38e6d Binary files /dev/null and b/src/main/resources/images/priorities_low.png differ diff --git a/src/main/resources/images/priorities_medium.png b/src/main/resources/images/priorities_medium.png new file mode 100644 index 00000000000..59d96906ea8 Binary files /dev/null and b/src/main/resources/images/priorities_medium.png differ diff --git a/src/main/resources/images/priorities_urgent.png b/src/main/resources/images/priorities_urgent.png new file mode 100644 index 00000000000..5746b319289 Binary files /dev/null and b/src/main/resources/images/priorities_urgent.png differ diff --git a/src/main/resources/images/right_click_copy_to_clipboard.png b/src/main/resources/images/right_click_copy_to_clipboard.png new file mode 100644 index 00000000000..1ce709a9ea9 Binary files /dev/null and b/src/main/resources/images/right_click_copy_to_clipboard.png differ diff --git a/src/main/resources/images/task_icon.png b/src/main/resources/images/task_icon.png new file mode 100644 index 00000000000..21ecee071ea Binary files /dev/null and b/src/main/resources/images/task_icon.png differ diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 36e6b001cd8..815b35f35a0 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -24,6 +24,17 @@ -fx-opacity: 1; } +.label-list-header-background { + -fx-background-color: #2a4158; +} + +.label-list-header { + -fx-font-size: 15pt; + -fx-font-family: "Segoe UI Semibold"; + -fx-text-fill: white; + -fx-opacity: 1; +} + .text-field { -fx-font-size: 12pt; -fx-font-family: "Segoe UI Semibold"; @@ -128,10 +139,32 @@ .cell_small_label { -fx-font-family: "Segoe UI"; - -fx-font-size: 13px; + -fx-font-size: 14px; -fx-text-fill: #010504; } +.cell_completion_done_label { + -fx-background-color: #34a853; + -fx-background-radius: 5; + -fx-font-family: "Segoe UI"; + -fx-font-size: 14px; + -fx-text-fill: #eaeaea; +} + +.cell_completion_not_done_label { + -fx-background-color: #ea4335; + -fx-background-radius: 5; + -fx-font-family: "Segoe UI"; + -fx-font-size: 14px; + -fx-text-fill: #eaeaea; +} + +.cell_priority_label { + -fx-font-family: "Segoe UI"; + -fx-font-size: 14px; + -fx-text-fill: #eaeaea; +} + .stack-pane { -fx-background-color: derive(#1d1d1d, 20%); } diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css index 17e8a8722cd..cd9cf694807 100644 --- a/src/main/resources/view/HelpWindow.css +++ b/src/main/resources/view/HelpWindow.css @@ -1,4 +1,12 @@ -#copyButton, #helpMessage { +#userGuideTitle, #copyClipboardFeatureTitle { + -fx-font-size: 12pt; + -fx-font-family: "Segoe UI Semibold"; + -fx-text-fill: white; +} + +#userGuideUrl, #copyClipboardFeatureContent, #copyButton { + -fx-font-size: 10pt; + -fx-font-family: "Segoe UI"; -fx-text-fill: white; } diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml index 5dea0adef70..b94dc4c7294 100644 --- a/src/main/resources/view/HelpWindow.fxml +++ b/src/main/resources/view/HelpWindow.fxml @@ -6,7 +6,11 @@ + + + + @@ -19,24 +23,60 @@ - + - - + + + + + + + + +