diff --git a/.github/check-line-endings.sh b/.github/check-line-endings.sh
index 3de67ea87f6..57ab7d3bbc9 100755
--- a/.github/check-line-endings.sh
+++ b/.github/check-line-endings.sh
@@ -1,8 +1,9 @@
#!/bin/sh
# Checks for prohibited line endings.
# Prohibited line endings: \r\n
+# Exclude .vcf files as the RFC states that they must use \r\n
-git grep --cached -I -n --no-color -P '\r$' -- ':/' |
+git grep --cached -I -n --no-color -P '\r$' -- ':/' ':/!*.vcf' |
awk '
BEGIN {
FS = ":"
diff --git a/.gitignore b/.gitignore
index 284c4ca7cd9..59f3b5f7ee2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,28 @@
# Gradle build files
/.gradle/
/build/
-src/main/resources/docs/
+/src/main/resources/docs/
+
+# Vscode files
+/.vscode/
# IDEA files
/.idea/
/out/
/*.iml
+/bin
# Storage/log files
+/exports/
/data/
/config.json
/preferences.json
/*.log.*
-hs_err_pid[0-9]*.log
+/hs_err_pid[0-9]*.log
# Test sandbox files
-src/test/data/sandbox/
+/src/test/data/sandbox/
# MacOS custom attributes files created by Finder
.DS_Store
-docs/_site/
+/docs/_site/
diff --git a/README.md b/README.md
index 16208adb9b6..9780b8f410a 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,15 @@
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
+[![CI Status](https://github.com/AY2425S1-CS2103-F10-3/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2425S1-CS2103-F10-3/tp/actions) [![codecov](https://codecov.io/gh/AY2425S1-CS2103-F10-3/tp/graph/badge.svg?token=XDT6OIN0I7)](https://codecov.io/gh/AY2425S1-CS2103-F10-3/tp)
![Ui](docs/images/Ui.png)
-* This is **a sample project for Software Engineering (SE) students**.
+* This is an **address book application catered towards B2B Sales Representatives in the Food and Beverage Industry**.
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.
+ * as a tool to more easily retrieve information from clients to improve overall workflow efficiency
+* The project builds on a 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/#contributing-to-se-edu) for more info.
+* It is named `BizBook` as it aims to improve the workflow of business to business dealings by prioritizing efficiency and offering features specific to this target demographic.
+* For the detailed documentation of this project, see the **[BizBook Website](https://ay2425s1-cs2103-f10-3.github.io/tp/)**.
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+* This projects icon was created using [canva](https://www.canva.com).
+
diff --git a/build.gradle b/build.gradle
index 0db3743584e..60a17a834cf 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ plugins {
id 'jacoco'
}
-mainClassName = 'seedu.address.Main'
+mainClassName = 'bizbook.Main'
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
@@ -41,7 +41,7 @@ task coverage(type: JacocoReport) {
}
dependencies {
- String jUnitVersion = '5.4.0'
+ String jUnitVersion = '5.10.0'
String javaFxVersion = '17.0.7'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
@@ -57,16 +57,23 @@ dependencies {
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
- implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.7.0'
- implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.7.4'
+ implementation 'com.googlecode.ez-vcard:ez-vcard:0.12.1'
+
+ implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.0'
+ implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.18.0'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: jUnitVersion
+ testImplementation 'org.mockito:mockito-core:4.8.0' // Mockito core
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'bizbook.jar'
}
defaultTasks 'clean', 'test'
+
+run {
+ enableAssertions = true
+}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index eb761a9b9a7..d35fe4c211b 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -418,6 +418,9 @@
+
+
+
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index ff3f04abd02..5530195eee8 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -9,51 +9,53 @@ You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
+### Nicholas Cheng De Fei
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/Nicholas-Cheng-De-Fei)]
+[[linkedin](https://www.linkedin.com/in/nicholas-cheng-)]
-* Role: Project Advisor
+- Role: Team Lead
+- Responsibilities: Project Coordination, VScode Expert
-### Jane Doe
+### Joel Tio
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[website](https://joelt.io)]
+[[github](https://github.com/joeltio)]
+[[linkedin](https://www.linkedin.com/in/joel-tio)]
-* Role: Team Lead
-* Responsibilities: UI
+- Role: Developer
+- Responsibilities: Code Quality, Git Expert
-### Johnny Doe
+### Lim Jia Wei
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](https://github.com/ITLimJiaWei)]
+[[linkedin](https://www.linkedin.com/in/jiawei88)]
-* Role: Developer
-* Responsibilities: Data
+- Role: Developer
+- Responsibilities: Testing, IntelliJ Expert
-### Jean Doe
+### Kenneth Teo
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/KennethTeo2002)]
+[[linkedin](https://www.linkedin.com/in/kenneth-teo-boon-jun)]
-* Role: Developer
-* Responsibilities: Dev Ops + Threading
+- Role: Developer
+- Responsibilities: Integration, Deliverables and deadlines
-### James Doe
+### Sheen
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/sheenkerr)]
+[[linkedin](https://www.linkedin.com/in/sheenkerr)]
-* Role: Developer
-* Responsibilities: UI
+- Role: Developer
+- Responsibilities: Documentation
diff --git a/docs/DevOps.md b/docs/DevOps.md
index d2fd91a6001..f28652df046 100644
--- a/docs/DevOps.md
+++ b/docs/DevOps.md
@@ -73,7 +73,7 @@ Any warnings or errors will be printed out to the console.
Here are the steps to create a new release.
-1. Update the version number in [`MainApp.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java).
+1. Update the version number in [`MainApp.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/bizbook/MainApp.java).
1. Generate a fat JAR file using Gradle (i.e., `gradlew shadowJar`).
1. Tag the repo with the version number. e.g. `v0.1`
1. [Create a new release using GitHub](https://help.github.com/articles/creating-releases/). Upload the JAR file you created.
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 743c65a49d2..b7ed0be0fcb 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,63 +2,65 @@
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}
+- {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+- [ez-vcard](https://github.com/mangstadt/ez-vcard) by [mangstadt](https://github.com/mangstadt/)
+- [mockito](https://github.com/mockito/mockito)
---------------------------------------------------------------------------------------------------------------------
+---
## **Setting up, getting started**
Refer to the guide [_Setting up and getting started_](SettingUp.md).
---------------------------------------------------------------------------------------------------------------------
+---
## **Design**
:bulb: **Tip:** The `.puml` files used to create diagrams in this document `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
-The ***Architecture Diagram*** given above explains the high-level design of the App.
+The **_Architecture Diagram_** given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
**Main components of the architecture**
-**`Main`** (consisting of classes [`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)) is in charge of the app launch and shut down.
-* At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
-* At shut down, it shuts down the other components and invokes cleanup methods where necessary.
+**`Main`** (consisting of classes [`Main`](https://github.com/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/Main.java) and [`MainApp`](https://github.com/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/MainApp.java)) is in charge of the app launch and shut down.
+
+- At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
+- At shut down, it shuts down the other components and invokes cleanup methods where necessary.
The bulk of the app's work is done by the following four components:
-* [**`UI`**](#ui-component): The UI of the App.
-* [**`Logic`**](#logic-component): The command executor.
-* [**`Model`**](#model-component): Holds the data of the App in memory.
-* [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk.
+- [**`UI`**](#ui-component): The UI of the App.
+- [**`Logic`**](#logic-component): The command executor.
+- [**`Model`**](#model-component): Holds the data of the App in memory.
+- [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk.
[**`Commons`**](#common-classes) represents a collection of classes used by multiple other 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 `delete 1`.
Each of the four main components (also shown in the diagram above),
-* defines its *API* in an `interface` with the same name as the Component.
-* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point.
+- defines its _API_ in an `interface` with the same name as the Component.
+- implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point.
For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
@@ -68,24 +70,24 @@ 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/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/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` 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/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2425S1-CS2103-F10-3/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`.
+- 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`.
### 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/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
@@ -95,89 +97,99 @@ The sequence diagram below illustrates the interactions within the `Logic` compo
![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png)
-
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
+
+
+:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
+
How the `Logic` component works:
1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command.
-1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
+2. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`.
+3. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve.
-1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
+4. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
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., `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.
### 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/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/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 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 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)
+- stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` 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 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 `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.
-
### 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/AY2425S1-CS2103-F10-3/tp/blob/master/src/main/java/bizbook/storage/Storage.java)
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`)
+
+- 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`)
### Common classes
-Classes used by multiple components are in the `seedu.address.commons` package.
+Classes used by multiple components are in the `bizbook.commons` package.
---------------------------------------------------------------------------------------------------------------------
+---
## **Implementation**
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### Undo/redo feature
-#### 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:
+The undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally in an `addressBookOlderVersionList` for the undo history and `addressBookNewerVersionList` for the redo history. Additionally, it implements the following operations:
-* `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.
+- `VersionedAddressBook#canRedo()` — Checks if there is a version to redo to.
+- `VersionedAddressBook#canUndo()` — Checks if there is a version to undo to.
+- `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.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+These operations are exposed in the `Model` interface as `Model#canRedo()`, `Model#canUndo()`, `Model#saveAddressBookVersion()`, `Model#revertAddressBookVersion()` and `Model#redoAddressBookVersion()` respectively.
+
+The `addressBookOlderVersionList` will only hold up to 5 seperate unique versions of the address book, therefore BizBook will only remember up till 5 previously executed commands that in some way have modified the address book.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
-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.
+Step 1. The user launches the application for the first time. The `addressBookOlderVersionList` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state. While the `addressBookNewerVersionList` will be empty.
![UndoRedoState0](images/UndoRedoState0.png)
-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.
+Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#saveAddressBookVersion()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookOlderVersionList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
![UndoRedoState1](images/UndoRedoState1.png)
-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`.
+Step 3. The user executes `add n/David …` to add a new person. The `add` command also calls `Model#saveAddressBookVersion()`, causing another modified address book state to be saved into the `addressBookOlderVersionList`.
![UndoRedoState2](images/UndoRedoState2.png)
@@ -185,7 +197,7 @@ Step 3. The user executes `add n/David …` to add a new person. The `add` co
-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 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#revertAddressBookVersion()`, which remove the item at the `currentStatePointer` and add it into the `addressBookNewerVersionList`. In the process the `currentStatePointer` moves left, points to the previous address book state, and restores the address book to that state.
![UndoRedoState3](images/UndoRedoState3.png)
@@ -206,17 +218,17 @@ Similarly, how an undo operation goes through the `Model` component is shown bel
![UndoSequenceDiagram](images/UndoSequenceDiagram-Model.png)
-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 `redo` command does the opposite — it calls `Model#redoAddressBookVersion()`, which removes the item at the `redoPointer` and adds it to the back of the `addressBookOlderVersionList`, it also shifts the `currentStatePointer` to the right as well as restores the address book to that state.
-
: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.
+
:information_source: **Note:** If the `redoPointer` is at index `addressBookNewerVersionList.size() - 1` or the list is empty, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedo()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
-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.
+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#saveAddressBookVersion()`, `Model#revertAddressBookVersion()` or `Model#redoAddressBookVersion()`. Thus, the `addressBookOlderVersionList` remains unchanged.
![UndoRedoState4](images/UndoRedoState4.png)
-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 6. The user executes `clear`, which calls `Model#saveAddressBookVersion()`. Since the `redoPointer` is pointing at an item in the `addressBookNewerVersionList`, all address book states in `addressBookNewerVersionList` 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.
![UndoRedoState5](images/UndoRedoState5.png)
@@ -224,111 +236,437 @@ The following activity diagram summarizes what happens when a user executes a ne
-#### Design considerations:
-**Aspect: How undo & redo executes:**
+## **Documentation, logging, testing, configuration, dev-ops**
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+- [Documentation guide](Documentation.md)
+- [Testing guide](Testing.md)
+- [Logging guide](Logging.md)
+- [Configuration guide](Configuration.md)
+- [DevOps guide](DevOps.md)
-* **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.
+---
-_{more aspects and alternatives to be added}_
+## **Appendix: Requirements**
-### \[Proposed\] Data archiving
+### Product scope
-_{Explain here how the data archiving feature will be implemented}_
+**Target user profile**:
+A sales and customer relations representative working in the F&B industry. In
+particular, this representative works with B2B sales.
---------------------------------------------------------------------------------------------------------------------
+- has a need to manage a significant number of business contacts
+- prefer desktop apps over other types
+- can type fast
+- prefers typing to mouse interactions
+- is reasonably comfortable using CLI apps
-## **Documentation, logging, testing, configuration, dev-ops**
+**Value proposition**: This product aims to streamline and simplify sales management for Food and Beverage outlets. By providing an organized, easy-to-use platform for managing business contacts, it helps sales representatives save time and improve efficiency.
-* [Documentation guide](Documentation.md)
-* [Testing guide](Testing.md)
-* [Logging guide](Logging.md)
-* [Configuration guide](Configuration.md)
-* [DevOps guide](DevOps.md)
+### User stories
---------------------------------------------------------------------------------------------------------------------
+Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-## **Appendix: Requirements**
+| Priority | As a … | I want to … | So that I can … |
+| -------- |------------------|-----------------------------------------------------------------------------|------------------------------------------------------------------------|
+| `* * *` | user | add a new contact | save the contact information of people |
+| `* * *` | user | delete a contact | free up space in my app |
+| `* * *` | user | view all contact | see the full list of contacts |
+| `* * *` | user | view a contact | retrieve contact information of a person |
+| `* * *` | user | save all contact | retain all information for when i reopen the app |
+| `* * *` | sales rep | have a low query time | avoid wasting much time querying my desired contact |
+| `* *` | user | find a person by name | locate details of persons without having to go through the entire list |
+| `* *` | user | search through my contacts | find a specific person |
+| `* *` | new user | see usage instructions | know how to use the app |
+| `* *` | user | edit contact | update contact with new information |
+| `* *` | user | delete a tag from a person | remove tags that are invalid or are not applicable to the person |
+| `* *` | user | sort contact by name | see whose contact I have saved |
+| `* *` | user | pin a specific contact | view them on a separate list |
+| `* *` | user | unpin a specific contact | clear the pin that is no longer needed |
+| `* *` | user | archive contact | hide less frequently used contacts without deleting them |
+| `* *` | user | be alerted when a contact already exist | avoid accidentally creating a duplicate |
+| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
+| `* *` | user | undo a command | fix a mistake I made |
+| `* *` | user | redo a command | revert back the changes I undid |
+| `* *` | new user | import all contact details into the app | start using without manual setup |
+| `* *` | sales rep | keep track of clients I have contacted by seeing when I last contacted them | avoid wasting time calling them again about the same product |
+| `* *` | sales rep | view my most popular/active clients | promote the new product |
+| `* *` | sales rep | remember the client's preferred products | recommend related products |
+| `* *` | sales rep | add notes to client's contact | keep track of my conversation with them |
+| `* *` | sales rep | edit notes saved to client's contact | keep track of my conversation with them |
+| `* *` | sales rep | delete notes from a client's contact | remove incorrect or outdated notes |
+| `* *` | sales rep | group my clients by industry | tell if sales are doing well in that industry among other metrics |
+| `* *` | sales rep | add tags to clients | categorize them |
+| `* *` | sales rep | keep note of my client's email addresses | potentially send promotions or survey forms |
+| `* *` | sales rep | export a list of contact emails | add them to a mailing list |
+| `* *` | sales rep | export my contacts | send it to my coworker who needs it for his work |
+| `* *` | sales rep | add a tag to multiple clients | tag the clients more easily |
+| `*` | user | sort contacts by name | locate a person easily |
+| `*` | experienced user | use keyboard shortcuts | navigate the app faster |
+| `*` | sales rep | contact my client quickly from the app | avoid typing numbers repeatedly on my _device_ |
+| `*` | user | use my previous command quickly | avoid retyping a command |
+| `*` | user | toggle my application between light and dark mode | see the application in my preferred theme |
-### Product scope
+### Use cases
-**Target user profile**:
+(For all use cases below, the **System** is the `Bizbook` and the **Actor** is the `user`, unless specified otherwise)
+
+**Use case: UC1 - Add a person**
-* 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
+**MSS**
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+1. Actor requests to add a new person.
+2. System shows details of the newly added person.
+ Use case ends.
-### User stories
+**Extensions**
-Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
+- 1a. The details entered about the new person are invalid.
-| 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 |
+ - 1a1. System shows an error message.
-*{More to be added}*
+ Use case ends.
-### Use cases
+- 1b. A person with the same identifier is already in contact list.
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+ - 1b1. System shows duplicate person message.
-**Use case: Delete a person**
+ Use case ends.
+
+**Use case: UC2 - List all people**
**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. Actor requests to list all people saved in the System.
+2. System shows a list of people.
Use case ends.
**Extensions**
-* 2a. The list is empty.
+- 1a. No contacts stored in the System.
Use case ends.
-* 3a. The given index is invalid.
+**Use case: UC3 - Delete a person**
+
+**MSS**
+
+1. Actor performs list all people (UC2).
+2. Actor requests to delete a specific person in the list.
+3. System shows details of deleted person.
+
+ Use case ends.
+
+**Extensions**
+
+- 2a. The specified person is invalid.
+
+ - 2a1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC4 - Delete a person**
+
+**MSS**
+
+1. Actor performs list all people (UC2).
+2. Actor requests to delete a specific tag from a person.
+3. System remove the tag from the person.
+
+ Use case ends.
+
+**Extensions**
+
+- 2a. The specified person is invalid.
+
+ - 2a1. System shows an error message.
+
+ Use case ends.
+
+- 2b. The specified tag does not exist.
+
+ - 2b1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC5 - View person contact**
+
+**MSS**
+
+1. Actor requests to see specific person's detail.
+2. System shows person's contact details.
+
+ Use case ends.
+
+**Extensions**
+
+- 1a. The specified person is invalid.
+
+ - 1a1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC6 - Find people**
+
+**MSS**
+
+1. Actor requests to find specific people.
+2. System shows a filtered list of people.
+
+ Use case ends.
+
+**Extensions**
+
+- 1a. No contacts match keywords.
+
+ Use case ends.
+
+**Use case: UC7 - Add note to a person contact**
+
+**MSS**
+
+1. Actor performs list all people (UC2).
+2. Actor requests to add a note to a specific person.
+3. System shows details of the newly added note to that person.
+
+ Use case ends.
+
+**Extensions**
+
+- 2a. The specified person is invalid.
+
+ - 2a1. System shows an error message.
+
+ Use case ends.
+
+- 2b. The note content is invalid.
+
+ - 2b1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC8 - Edit a note of a person contact**
+
+**MSS**
+
+1. Actor performs list all people (UC2).
+2. Actor requests to edit a note to a specific person.
+3. System shows details of the newly edited note of that person.
+
+ Use case ends.
+
+**Extensions**
+
+- 2a. The specified person is invalid.
+
+ - 2a1. System shows an error message.
+
+ Use case ends.
+
+- 2b. The note index is invalid.
+
+ - 2b1. System shows an error message.
+
+ Use case ends.
+
+- 2c. The note content is invalid.
+
+ - 2c1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC9 - Delete note from a person contact**
+
+**MSS**
+
+1. Actor performs list all people (UC2).
+2. Actor requests to delete a specific note from a specific person.
+3. System shows updated details excluding deleted note from that person.
+
+ Use case ends.
+
+**Extensions**
+
+- 2a. The specified person is invalid.
+
+ - 2a1. System shows an error message.
+
+ Use case ends.
+
+- 2b. The note index is invalid.
+
+ - 2b1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC10 - Pin a person**
+
+**MSS**
+
+1. Actor performs list all people (UC2).
+2. Actor requests to pin a specific person.
+3. System shows details of newly pinned person.
+
+**Extension**
+
+- 2a. The specified person is invalid.
+
+ - 2a1. System shows an error message.
+
+ Use case ends.
+
+- 2b. The person is already pinned.
+
+ - 2b1. System shows duplicated pin message.
+
+ Use case ends.
+
+**Use case: UC11 - Unpin a person**
- * 3a1. AddressBook shows an error message.
+_Similar to UC10 except without extension 2b._
- Use case resumes at step 2.
+**Use case: UC12 - Undo a command**
-*{More to be added}*
+**MSS**
+
+1. Actor performs a command that updates the System.
+2. System executes the command.
+3. Actor requests to undo the recently executed command.
+4. System reverts changes made by the actor.
+
+ Use case ends.
+
+**Extensions**
+
+- 3a. There is no version to revert to.
+
+ - 3a1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC13 - Redo a command**
+
+**MSS**
+
+1. Actor performs a command that updates the System.
+2. System executes the command.
+3. Actor requests to undo the recently executed command.
+4. System reverts changes made by the actor.
+5. Actor requests to redo the recently executed undo command.
+6. System reverts changes made by the actor.
+
+ Use case ends.
+
+**Extensions**
+
+- 5a. There is no version to revert to.
+
+ - 5a1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC14 - Export contact list**
+
+**MSS**
+
+1. Actor requests to export contact list to a specific file.
+2. System exports the contact information into the file.
+
+ Use case ends.
+
+**Extensions**
+
+- 1a. System detects that the directory does not exist.
+
+ - 1a1. System creates the directory.
+
+ Use case resumes from step 2.
+
+- 1b. System detects that the file is used by another process.
+
+ - 1b1. System shows an error message.
+
+ Use case ends.
+
+**Use case: UC15 - Import a contact list**
+
+**MSS**
+
+1. Actor requests to import a contact list from a specific file.
+2. System imports the contact information into the file.
+
+ Use case ends.
+
+**Extensions**
+
+- 1a. System detects that the file does not exist.
+
+ - 1a1. System shows an error message
+
+ Use case ends.
+
+- 1b. System detects that the file is not supported by the program
+
+ - 1b1. System shows an error message
+
+ Use case ends.
+
+**Use case: UC16 - Toggle application's theme**
+
+**MSS**
+
+1. Actor toggle the system's theme.
+2. System changes theme.
+
+ Use case ends.
+
+**Use case: UC17 - Command History**
+
+**MSS**
+
+1. Actor inputs a command into the System.
+2. System processes the command and confirms its success.
+3. Actor presses the "Up" arrow key to retrieve and re-populate the previous command in the input field.
+
+ Use case ends.
+
+**Extensions**
+
+- 2a. Command fails.
+
+ - 2a1. System displays an error message indicating the failure reason.
+
+ Use case resumes from step 1.
+
+- 3a. Multiple previous commands available.
+
+ - 3a1. Actor presses the "Up" arrow key multiple times to cycle through the command history.
+ - 3a2. System displays each previous command in sequence.
+
+ Use case ends.
### Non-Functional Requirements
-1. Should work on any _mainstream OS_ as long as it has Java `17` 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.
+1. The system should work on any _mainstream OS_ as long as it has Java `17` or above installed.
+2. The system should be able to hold up to 1000 contacts without a noticeable sluggishness in performance for typical usage.
+3. The system should be developed in a modular way for easier updates and bug fixes.
+4. The system should ensure data consistency across all instances.
+5. The system should continue functioning in the event of a missing or corrupted save file.
+6. The system should encrypt sensitive data to follow data protection laws.
+7. The interface should be intuitive and easy to use.
-*{More to be added}*
+_{More to be added}_
### Glossary
-* **Mainstream OS**: Windows, Linux, Unix, MacOS
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+- **Mainstream OS**: Windows, Linux, Unix, MacOS
+- **Private contact detail**: A contact detail that is not meant to be shared with others
+- **Device**: system with dialing and calling capabilities
---------------------------------------------------------------------------------------------------------------------
+---
## **Appendix: Instructions for manual testing**
@@ -343,40 +681,40 @@ testers are expected to do more *exploratory* testing.
1. Initial launch
- 1. Download the jar file and copy into an empty folder
+ 1a. 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.
+ 2b. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-1. Saving window preferences
+2. Saving window preferences
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+ 2a. Resize the window to an optimum size. Move the window to a different location. Close the window.
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+ 2b. Re-launch the app by double-clicking the jar file.
+ Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
+3. _{ more test cases … }_
### Deleting a person
1. Deleting a person while all persons are being shown
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+ 1a. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
- 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.
+ 1b. 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.
+ 1c. Test case: `delete 0`
+ Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+ 1d. 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 … }_
+2. _{ more test cases … }_
### Saving data
1. Dealing with missing/corrupted data files
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+ 1a. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
-1. _{ more test cases … }_
+2. _{ more test cases … }_
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index bac5eb36d35..d83abf139ec 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -216,6 +216,8 @@ GEM
nokogiri (1.16.5)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
+ nokogiri (1.16.5-x64-mingw32)
+ racc (~> 1.4)
octokit (4.25.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
@@ -254,6 +256,7 @@ GEM
unf_ext (0.0.8.2)
unf_ext (0.0.8.2-x64-mingw32)
unicode-display_width (1.8.0)
+ wdm (0.1.1)
webrick (1.8.1)
PLATFORMS
@@ -263,7 +266,8 @@ PLATFORMS
DEPENDENCIES
github-pages
jekyll
+ wdm (~> 0.1.0)
webrick
BUNDLED WITH
- 2.1.4
+ 2.5.19
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 9f832a19674..07f3a7a0d88 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -3,30 +3,33 @@ layout: page
title: Setting up and getting started
---
-* Table of Contents
-{:toc}
+- Table of Contents
+ {:toc}
-
---------------------------------------------------------------------------------------------------------------------
+---
## Setting up the project in your computer
-
:exclamation: **Caution:**
+
+
+:exclamation: **Caution:**
Follow the steps in the following guide precisely. Things will not work out if you deviate in some steps.
+
First, **fork** this repo, and **clone** the fork into your computer.
If you plan to use Intellij IDEA (highly recommended):
+
1. **Configure the JDK**: Follow the guide [_[se-edu/guides] IDEA: Configuring the JDK_](https://se-education.org/guides/tutorials/intellijJdk.html) to ensure Intellij is configured to use **JDK 17**.
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.
+ :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 `bizbook.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
---------------------------------------------------------------------------------------------------------------------
+---
## Before writing code
@@ -34,7 +37,9 @@ If you plan to use Intellij IDEA (highly recommended):
If using IDEA, follow the guide [_[se-edu/guides] IDEA: Configuring the code style_](https://se-education.org/guides/tutorials/intellijCodeStyle.html) to set up IDEA's coding style to match ours.
-
:bulb: **Tip:**
+
+
+ :bulb: **Tip:**
Optionally, you can follow the guide [_[se-edu/guides] Using Checkstyle_](https://se-education.org/guides/tutorials/checkstyle.html) to find how to use the CheckStyle within IDEA e.g., to report problems _as_ you write code.
@@ -45,11 +50,4 @@ If you plan to use Intellij IDEA (highly recommended):
1. **Learn the design**
- When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [AddressBook’s architecture](DeveloperGuide.md#architecture).
-
-1. **Do the tutorials**
- These tutorials will help you get acquainted with the codebase.
-
- * [Tracing code](tutorials/TracingCode.md)
- * [Adding a new command](tutorials/AddRemark.md)
- * [Removing fields](tutorials/RemovingFields.md)
+ When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [BizBook’s architecture](DeveloperGuide.md#architecture).
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..c677257858e 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. `bizbook.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. `bizbook.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. `bizbook.logic.LogicManagerTest`
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 84b4ddc4e40..f1b49d33c57 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,41 +3,41 @@ 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.
+BizBook (BB) 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, BB can get your contact management tasks done faster than traditional GUI apps.
-* Table of Contents
-{:toc}
+- Table of Contents
+ {:toc}
---------------------------------------------------------------------------------------------------------------------
+---
## Quick start
1. Ensure you have Java `17` or above installed in your Computer.
-1. Download the latest `.jar` file from [here](https://github.com/se-edu/addressbook-level3/releases).
+2. Download the latest `.jar` file from [here](https://github.com/AY2425S1-CS2103-F10-3/tp/releases).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+3. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
+4. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar bizbook.jar` command to run the application.
A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
![Ui](images/Ui.png)
-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.
+5. 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.
+ - `list` : Lists all contacts.
- * `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.
+ - `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.
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+ - `delete 3` : Deletes the 3rd contact shown in the current list.
- * `clear` : Deletes all contacts.
+ - `clear` : Deletes all contacts.
- * `exit` : Exits the app.
+ - `exit` : Exits the app.
-1. Refer to the [Features](#features) below for details of each command.
+6. Refer to the [Features](#features) below for details of each command.
---------------------------------------------------------------------------------------------------------------------
+---
## Features
@@ -45,33 +45,39 @@ 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.
+- 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.
+- 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.
+- 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.
-* Parameters can be in any order.
+- Parameters can be in any order.
e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
+- Command keywords are case insensitive.
+ e.g. `add` and `ADD` are all acceptable.
+
+- Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
-* If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines as space characters surrounding line-breaks may be omitted when copied over to the application.
+- If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines as space characters surrounding line-breaks may be omitted when copied over to the application.
### Viewing help : `help`
-Shows a message explaning how to access the help page.
+Shows a table of basic commands and their usage syntax.
+
+Redirect link to user guide which explains the commands in detail is also provided below.
+
+In the event that redirect is unavailable due to OS/browser restrictions, URL will be copied to clipboard as the fail-safe.
![help message](images/helpMessage.png)
Format: `help`
-
### Adding a person: `add`
Adds a person to the address book.
@@ -83,8 +89,9 @@ A person can have any number of tags (including 0)
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`
+
+- `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`
### Listing all persons : `list`
@@ -98,16 +105,17 @@ Edits an existing person in the address book.
Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
-* 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.
+- 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.
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.
+
+- `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.
### Locating persons by name: `find`
@@ -115,16 +123,17 @@ Finds persons whose names contain any of the given keywords.
Format: `find KEYWORD [MORE_KEYWORDS]`
-* 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).
+- 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.
+- Partial words will be matched e.g. `Han` will 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`
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
+
+- `find John` returns `john`, `John Doe` and `Johnny`
+- `find alex david` returns `Alex Yeoh`, `David Li`
![result for 'find alex david'](images/findAlexDavidResult.png)
### Deleting a person : `delete`
@@ -133,13 +142,196 @@ Deletes the specified person from the address book.
Format: `delete INDEX`
-* Deletes 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, …
+- Deletes 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, …
+
+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.
+
+### Delete a Tag of an existing contact: `deletetag`
+
+Deletes a tag from a person in the address book.
+
+Format: `deletetag INDEX t/[TAG]`
+
+- Deletes the `TAG` for 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, …
+- The tag **must be a existing tag** on the person.
+
+Examples:
+
+- `deletetag 1 t/friends`
+- `deletetag 2 t/Client`
+
+### Adding Notes to an existing contact: `addnote`
+
+Adds a note to a person in the address book.
+
+Format: `addnote INDEX n/[NOTE]`
+
+
:bulb: **Tip:**
+A person can have any number of notes (including 0)
+
+
+- Add note to 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, …
+
+Examples:
+
+- `addnote 1 n/Supplier 1`
+- `addnote 2 n/Supplier 2`
+
+### Edit a Note of an existing contact: `editnote`
+
+Edits a note of a person in the address book.
+
+Format: `editnote INDEX i/NOTE_INDEX n/[NOTE]`
+
+- Edits the note at the specified `NOTE_INDEX` of the person at the specified `INDEX`.
+ -The index refers to the index number shown in the displayed person list.
+- The note index refers to the index number shown in the notes list of the contact details of the displayed person.
+- The index and notes index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+
+- `editnote 1 i/1 n/Customer 1`
+- `editnote 2 i/1 n/Customer 2`
+
+### Deleting a note from an existing contact: `deletenote`
+
+Deletes a note from a person in the address book.
+
+Format: `deletnote INDEX n/[NOTE_INDEX]`
+
+- Delete note from the person at the specified `INDEX` and specified `NOTE_INDEX`.
+- The index refers to the index number shown in the displayed person list.
+- The note index refers to the index number shown in the notes list of the contact details of the displayed person.
+- The index and note index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+
+- `deletenote 1 i/1`
+- `deletenote 2 i/2`
+
+### Viewing an existing contact's details : `view`
+
+Views the details of a person in the address book.
+
+Format: `view INDEX`
+
+- Views the details of 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, ...
+- The index **must be within the range** shown on the displayed person list.
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.
+
+- `view 1` shows the contact details of the first person shown on the displayed person list.
+
+### Pinning a contact: `pin`
+
+Pins the contact of a person into a dedicated panel.
+
+Format: `pin INDEX`
+
+- Pin the contact of the person at the specified `INDEX`.
+- The index refers to the index number shown in the displayed person list, not the pinned list.
+- The index **must be a positive integer** 1, 2, 3, ...
+- The index **must be within the range** shown on the displayed person list.
+
+Examples:
+
+- `pin 1` pins the contact of the first person shown on the displayed person list into the pinned person list.
+
+### Unpinning a contact: `unpin`
+
+Unpins the contact of a person from the pinned list.
+
+Format: `unpin INDEX`
+
+- Unpin the contact of the person at the specified `INDEX`.
+- The index refers to the index number shown in the pinned list, not the displayed person list.
+- The index **must be a positive integer** 1, 2, 3, ...
+- The index **must be within the range** shown on the pinned list.
+
+Examples:
+
+- `unpin 1` unpins the contact of the first person shown on the pinned person list.
+
+### Undoing a previously executed command: `undo`
+
+Undoes the previous command that was executed.
+
+Format: `undo`
+
+- The undo feature saves the **5 most recent executed commands**.
+- The undo feature only tracks commands that **modifies the address book**.
+- The undo feature will clear the focus person panel upon execution.
+
+Examples of commands tracked by undo:
+- `add`
+- `delete`
+- `clear`
+- `edit`
+- `pin`
+
+### Redoing a previously executed undo command: `redo`
+
+Redoes the previous undo command that was executed.
+
+Format: `redo`
+
+- The redo feature saves the **5 most recent executed undo commands**.
+- The redo feature only tracks changed made by the undo command
+- The redo feature will clear the focus person panel upon execution.
+
+### Importing a contact list : `import`
+
+Imports a file containing contacts from a specified file type and overwrites all
+existing contacts with the imported data.
+
+Format: `import f/FILETYPE p/PATH`
+
+- Imports the contact list from the specified `FILETYPE`.
+- The only supported file type currently is **vcf**.
+
+Examples:
+
+- `import f/vcf p/bizbook.vcf` imports the contacts from the file `bizbook.vcf` that is located in the same folder as this application.
+- `import f/vcf p//Users/Name/myAddress.bcf` imports the contacts from the file located at `/Users/Name/myAddress.bcf`
+
+### Exporting the contact list : `export`
+
+Exports the contacts in the contact list into the specified file type. The file will be named bizbook.<file extension> and will be located in a folder named exports.
+
+Format: `export f/FILETYPE`
+
+- Exports the contact list into the specified `FILETYPE`.
+- The file type must be **either csv or vcf**.
+
+Examples:
+
+- `export f/csv` exports the contact list into a csv file.
+- `export f/vcf` exports the contact list into a vcf file.
+
+### Changing the application's theme : `toggle`
+
+Changes the application theme from light to dark or from dark to light.
+
+Format: `toggle`
+
+- If application is currently in light mode, toggle command will set it to dark mode.
+- If application is currently in dark mode, toggle command will set it to light mode.
+- Please note that our application does not save your theme preference, so it will always open in dark mode by default.
+
+Examples:
+
+- `toggle` changes the application theme.
### Clearing all entries : `clear`
@@ -163,37 +355,49 @@ AddressBook data are saved automatically as a JSON file `[JAR file location]/dat
: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. Hence, it is recommended to take a backup of the file before editing it.
-Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside of the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
+Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
### Archiving data files `[coming in v2.0]`
_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.
---------------------------------------------------------------------------------------------------------------------
+---
## Known issues
1. **When using multiple screens**, if you move the application to a secondary screen, and later switch to using only the primary screen, the GUI will open off-screen. The remedy is to delete the `preferences.json` file created by the application before running the application again.
2. **If you minimize the Help Window** and then run the `help` command (or use the `Help` menu, or the keyboard shortcut `F1`) again, the original Help Window will remain minimized, and no new Help Window will appear. The remedy is to manually restore the minimized Help Window.
---------------------------------------------------------------------------------------------------------------------
+---
## 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`
+| 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` |
+| **List** | `list` |
+| **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` |
+| **Delete** | `delete INDEX` e.g., `delete 3` |
+| **Deletetag** | `deletetag INDEX t/[TAG]` e.g. `deletetag 1 t/Client` |
+| **Addnote** | `addnote INDEX n/[NOTE]` e.g. `addnote 1 n/Customer 1` |
+| **Editnote** | `editnote INDEX i/NOTE_INDEX n/[NOTE]` e.g. `editnote 1 i/1 n/Customer 1` |
+| **Deletenote** | `deletenote INDEX i/[NOTE_INDEX]` e.g. `deletenote 1 i/1` |
+| **View** | `view INDEX` e.g. `view 1` |
+| **Pin** | `pin INDEX` e.g. `pin 1` |
+| **Unpin** | `unpin INDEX` e.g. `unpin 1` |
+| **Undo** | `undo` |
+| **Redo** | `redo` |
+| **Toggle** | `toggle` |
+| **Export** | `export f/FILETYPE` e.g. `export f/csv` |
+| **Import** | `import f/FILETYPE p/PATH` e.g. `import f/vcf p/myVcf.vcf` |
+| **Clear** | `clear` |
+| **Help** | `help` |
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..9009f20da98 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "BB"
theme: minima
header_pages:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..fc9ce25c3e7 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: "BizBook";
font-size: 32px;
}
}
diff --git a/docs/diagrams/ArchitectureSequenceDiagram2.puml b/docs/diagrams/ArchitectureSequenceDiagram2.puml
new file mode 100644
index 00000000000..7dcf0965e98
--- /dev/null
+++ b/docs/diagrams/ArchitectureSequenceDiagram2.puml
@@ -0,0 +1,27 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+Actor User as user USER_COLOR
+Participant ":UI" as ui UI_COLOR
+Participant ":Logic" as logic LOGIC_COLOR
+Participant ":Model" as model MODEL_COLOR
+
+user -[USER_COLOR]> ui : "export f/csv"
+activate ui UI_COLOR
+
+ui -[UI_COLOR]> logic : execute("export f/csv")
+activate logic LOGIC_COLOR
+
+logic -[LOGIC_COLOR]> model : getFilteredPersonList()
+activate model MODEL_COLOR
+
+model -[MODEL_COLOR]-> logic
+deactivate model
+
+logic --[LOGIC_COLOR]> ui
+deactivate logic
+
+ui--[UI_COLOR]> user
+deactivate ui
+@enduml
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 598474a5c82..5cadccc7cc5 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -13,6 +13,7 @@ UniqueTagList -right-> "*" Tag
UniquePersonList -right-> Person
Person -up-> "*" Tag
+Person -right->"*" Note
Person *--> Name
Person *--> Phone
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 5241e79d7da..1b6fdc7948f 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -8,6 +8,7 @@ participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
participant "r:CommandResult" as CommandResult LOGIC_COLOR
+
end box
box Model MODEL_COLOR_T1
@@ -34,7 +35,7 @@ create DeleteCommand
DeleteCommandParser -> DeleteCommand
activate DeleteCommand
-DeleteCommand --> DeleteCommandParser :
+DeleteCommand --> DeleteCommandParser
deactivate DeleteCommand
DeleteCommandParser --> AddressBookParser : d
@@ -49,7 +50,13 @@ deactivate AddressBookParser
LogicManager -> DeleteCommand : execute(m)
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : getFilteredPersonList()
+activate Model
+
+Model --> DeleteCommand
+deactivate Model
+
+DeleteCommand -> Model : deletePerson(p)
activate Model
Model --> DeleteCommand
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 0de5673070d..17589892322 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -19,6 +19,7 @@ Class Email
Class Name
Class Phone
Class Tag
+Class Note
Class I #FFFFFF
}
@@ -42,6 +43,7 @@ Person *--> Phone
Person *--> Email
Person *--> Address
Person *--> "*" Tag
+Person *--> "*" Note
Person -[hidden]up--> I
UniquePersonList -[hidden]right-> I
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index a821e06458c..e253578bd6c 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -20,6 +20,7 @@ Class JsonAddressBookStorage
Class JsonSerializableAddressBook
Class JsonAdaptedPerson
Class JsonAdaptedTag
+Class JsonAdaptedNote
}
}
@@ -39,5 +40,6 @@ JsonAddressBookStorage .up.|> AddressBookStorage
JsonAddressBookStorage ..> JsonSerializableAddressBook
JsonSerializableAddressBook --> "*" JsonAdaptedPerson
JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonAdaptedPerson --> "*" JsonAdaptedNote
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..f50c51d7186 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -13,8 +13,12 @@ Class HelpWindow
Class ResultDisplay
Class PersonListPanel
Class PersonCard
+Class ContactDetails
Class StatusBarFooter
Class CommandBox
+Class SearchBox
+Class PinnedPersonListPanel
+Class PinnedPersonCard
}
package Model <> {
@@ -30,31 +34,44 @@ HiddenOutside ..> Ui
UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
+
MainWindow *-down-> "1" CommandBox
+MainWindow *-down-> "1" SearchBox
MainWindow *-down-> "1" ResultDisplay
MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" PinnedPersonListPanel
MainWindow *-down-> "1" StatusBarFooter
-MainWindow --> "0..1" HelpWindow
+MainWindow -down-> "0..1" HelpWindow
+MainWindow *-down-> "0..1" ContactDetails
PersonListPanel -down-> "*" PersonCard
+PinnedPersonListPanel -down-> "*" PinnedPersonCard
MainWindow -left-|> UiPart
+ContactDetails -down-|> UiPart
+
+ResultDisplay -down-|> UiPart
+CommandBox -down-|> UiPart
+SearchBox -down-|> UiPart
+PersonListPanel -down-|> UiPart
+PersonCard -down-|> UiPart
+PinnedPersonListPanel -down-|> UiPart
+PinnedPersonCard -down-|> UiPart
+StatusBarFooter -down-|> UiPart
+HelpWindow -down-|> UiPart
-ResultDisplay --|> UiPart
-CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
-StatusBarFooter --|> UiPart
-HelpWindow --|> UiPart
+PersonCard .down.> Model
+PinnedPersonCard .down.> Model
+ContactDetails .down.> Model
-PersonCard ..> Model
UiManager -right-> Logic
-MainWindow -left-> Logic
+MainWindow -right-> Logic
PersonListPanel -[hidden]left- HelpWindow
-HelpWindow -[hidden]left- CommandBox
+HelpWindow -[hidden]left- SearchBox
+SearchBox -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
-MainWindow -[hidden]-|> UiPart
+MainWindow -[hidden]down-|> UiPart
@enduml
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
index 43a45903ac9..a656ab398a8 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/UndoRedoState0.puml
@@ -6,15 +6,17 @@ skinparam ClassBackgroundColor #FFFFAA
title Initial state
-package States {
+package UndoStateList <> {
class State1 as "ab0:AddressBook"
class State2 as "ab1:AddressBook"
class State3 as "ab2:AddressBook"
}
+
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-hide State2
-hide State3
+
+hide UndoStateList.State2
+hide UndoStateList.State3
class Pointer as "Current State" #FFFFFF
Pointer -up-> State1
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
index 5a41e9e1651..5b4fc4b8da3 100644
--- a/docs/diagrams/UndoRedoState1.puml
+++ b/docs/diagrams/UndoRedoState1.puml
@@ -6,7 +6,7 @@ skinparam ClassBackgroundColor #FFFFAA
title After command "delete 5"
-package States <> {
+package UndoStateList <> {
class State1 as "ab0:AddressBook"
class State2 as "ab1:AddressBook"
class State3 as "ab2:AddressBook"
@@ -15,7 +15,7 @@ package States <> {
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-hide State3
+hide UndoStateList.State3
class Pointer as "Current State" #FFFFFF
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
index ad32fce1b0b..e0a4e91d6c7 100644
--- a/docs/diagrams/UndoRedoState2.puml
+++ b/docs/diagrams/UndoRedoState2.puml
@@ -6,7 +6,7 @@ skinparam ClassBackgroundColor #FFFFAA
title After command "add n/David"
-package States <> {
+package UndoStateList <> {
class State1 as "ab0:AddressBook"
class State2 as "ab1:AddressBook"
class State3 as "ab2:AddressBook"
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml
index 9187a690036..fc7b1e021b0 100644
--- a/docs/diagrams/UndoRedoState3.puml
+++ b/docs/diagrams/UndoRedoState3.puml
@@ -6,16 +6,22 @@ skinparam ClassBackgroundColor #FFFFAA
title After command "undo"
-package States <> {
+package UndoStateList <> {
class State1 as "ab0:AddressBook"
class State2 as "ab1:AddressBook"
- class State3 as "ab2:AddressBook"
}
State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
+
+package RedoStateList <> {
+ class State3 as "ab2:AddressBook"
+}
+
+class RedoPointer as "Redo Pointer" #FFFFFF
+
+RedoPointer -up-> State3
@end
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml
index 2bc631ffcd0..06e2aa24acd 100644
--- a/docs/diagrams/UndoRedoState4.puml
+++ b/docs/diagrams/UndoRedoState4.puml
@@ -6,16 +6,22 @@ skinparam ClassBackgroundColor #FFFFAA
title After command "list"
-package States <> {
+package UndoStateList <> {
class State1 as "ab0:AddressBook"
class State2 as "ab1:AddressBook"
- class State3 as "ab2:AddressBook"
}
State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
+
+package RedoStateList <> {
+ class State3 as "ab2:AddressBook"
+}
+
+class RedoPointer as "Redo Pointer" #FFFFFF
+
+RedoPointer -up-> State3
@end
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
index e77b04104aa..63c464b5516 100644
--- a/docs/diagrams/UndoRedoState5.puml
+++ b/docs/diagrams/UndoRedoState5.puml
@@ -6,7 +6,7 @@ skinparam ClassBackgroundColor #FFFFAA
title After command "clear"
-package States <> {
+package UndoStateList <> {
class State1 as "ab0:AddressBook"
class State2 as "ab1:AddressBook"
class State3 as "ab3:AddressBook"
@@ -18,5 +18,5 @@ State2 -[hidden]right-> State3
class Pointer as "Current State" #FFFFFF
Pointer -up-> State3
-note right on link: State ab2 deleted.
+note right on link: RedoStateList will be cleared.
@end
diff --git a/docs/diagrams/UndoSequenceDiagram-Logic.puml b/docs/diagrams/UndoSequenceDiagram-Logic.puml
index e57368c5159..feb235b50ef 100644
--- a/docs/diagrams/UndoSequenceDiagram-Logic.puml
+++ b/docs/diagrams/UndoSequenceDiagram-Logic.puml
@@ -30,7 +30,7 @@ deactivate AddressBookParser
LogicManager -> UndoCommand : execute()
activate UndoCommand
-UndoCommand -> Model : undoAddressBook()
+UndoCommand -> Model : revertAddressBookVersion()
activate Model
Model --> UndoCommand
diff --git a/docs/diagrams/UndoSequenceDiagram-Model.puml b/docs/diagrams/UndoSequenceDiagram-Model.puml
index 54d83208cb8..8c116174a60 100644
--- a/docs/diagrams/UndoSequenceDiagram-Model.puml
+++ b/docs/diagrams/UndoSequenceDiagram-Model.puml
@@ -7,13 +7,12 @@ participant ":Model" as Model MODEL_COLOR
participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR
end box
-[-> Model : undoAddressBook()
+[-> Model : revertAddressBookVersion()
activate Model
Model -> VersionedAddressBook : undo()
activate VersionedAddressBook
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
VersionedAddressBook --> Model :
deactivate VersionedAddressBook
diff --git a/docs/images/ArchitectureSequenceDiagram2.png b/docs/images/ArchitectureSequenceDiagram2.png
new file mode 100644
index 00000000000..40a156993c6
Binary files /dev/null and b/docs/images/ArchitectureSequenceDiagram2.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 02a42e35e76..7f5b9858c2b 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index ac2ae217c51..e0fe4ba56da 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index a19fb1b4ac8..0cc9bc26da3 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 18fa4d0d51f..c6441cda087 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..5b7399164bc 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 11f06d68671..6b7f0aa1401 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png
index c5f91b58533..790e999288b 100644
Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ
diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png
index 2d3ad09c047..4bc9f9d78a5 100644
Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ
diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png
index 20853694e03..e9eda912914 100644
Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ
diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png
index 1a9551b31be..bad4f5f879e 100644
Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ
diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png
index 46dfae78c94..a5899fee1db 100644
Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ
diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png
index f45889b5fdf..56ec43b3fd4 100644
Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ
diff --git a/docs/images/UndoSequenceDiagram-Logic.png b/docs/images/UndoSequenceDiagram-Logic.png
index 78e95214294..a90bc4232e7 100644
Binary files a/docs/images/UndoSequenceDiagram-Logic.png and b/docs/images/UndoSequenceDiagram-Logic.png differ
diff --git a/docs/images/UndoSequenceDiagram-Model.png b/docs/images/UndoSequenceDiagram-Model.png
index f0f3da6ae50..e8b56c3e637 100644
Binary files a/docs/images/UndoSequenceDiagram-Model.png and b/docs/images/UndoSequenceDiagram-Model.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..5f9133ebd6b 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/itlimjiawei.png b/docs/images/itlimjiawei.png
new file mode 100644
index 00000000000..fc4500be3ca
Binary files /dev/null and b/docs/images/itlimjiawei.png differ
diff --git a/docs/images/joeltio.png b/docs/images/joeltio.png
new file mode 100644
index 00000000000..bdba6479eb1
Binary files /dev/null and b/docs/images/joeltio.png differ
diff --git a/docs/images/kennethteo2002.png b/docs/images/kennethteo2002.png
new file mode 100644
index 00000000000..86bc34e7e1e
Binary files /dev/null and b/docs/images/kennethteo2002.png differ
diff --git a/docs/images/nicholas-cheng-de-fei.png b/docs/images/nicholas-cheng-de-fei.png
new file mode 100644
index 00000000000..224ab5e034f
Binary files /dev/null and b/docs/images/nicholas-cheng-de-fei.png differ
diff --git a/docs/images/sheenkerr.png b/docs/images/sheenkerr.png
new file mode 100644
index 00000000000..45260a8025f
Binary files /dev/null and b/docs/images/sheenkerr.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..2fc9201858a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,20 @@
---
layout: page
-title: AddressBook Level-3
+title: BizBook
---
-
-[![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/AY2425S1-CS2103-F10-3/tp/actions/workflows/gradle.yml/badge.svg?branch=master)](https://github.com/AY2425S1-CS2103-F10-3/tp/actions/workflows/gradle.yml)
+[![codecov](https://codecov.io/gh/AY2425S1-CS2103-F10-3/tp/graph/badge.svg?token=XDT6OIN0I7)](https://codecov.io/gh/AY2425S1-CS2103-F10-3/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).
+**BizBook 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).
-* 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 BizBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing BizBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5), [Mockito](https://github.com/mockito/mockito)
+
diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/bizbook/AppParameters.java
similarity index 92%
rename from src/main/java/seedu/address/AppParameters.java
rename to src/main/java/bizbook/AppParameters.java
index 3d603622d4e..c3befd7de45 100644
--- a/src/main/java/seedu/address/AppParameters.java
+++ b/src/main/java/bizbook/AppParameters.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package bizbook;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -6,10 +6,10 @@
import java.util.Objects;
import java.util.logging.Logger;
+import bizbook.commons.core.LogsCenter;
+import bizbook.commons.util.FileUtil;
+import bizbook.commons.util.ToStringBuilder;
import javafx.application.Application;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.commons.util.ToStringBuilder;
/**
* Represents the parsed command-line parameters given to the application.
diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/bizbook/Main.java
similarity index 96%
rename from src/main/java/seedu/address/Main.java
rename to src/main/java/bizbook/Main.java
index 9461d6da769..c1aae614d2e 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/bizbook/Main.java
@@ -1,9 +1,9 @@
-package seedu.address;
+package bizbook;
import java.util.logging.Logger;
+import bizbook.commons.core.LogsCenter;
import javafx.application.Application;
-import seedu.address.commons.core.LogsCenter;
/**
* The main entry point to the application.
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/bizbook/MainApp.java
similarity index 85%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/bizbook/MainApp.java
index 678ddc8c218..db37b9c9b49 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/bizbook/MainApp.java
@@ -1,35 +1,35 @@
-package seedu.address;
+package bizbook;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.logging.Logger;
+import bizbook.commons.core.Config;
+import bizbook.commons.core.LogsCenter;
+import bizbook.commons.core.Version;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.commons.util.ConfigUtil;
+import bizbook.commons.util.StringUtil;
+import bizbook.logic.Logic;
+import bizbook.logic.LogicManager;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.UserPrefs;
+import bizbook.model.util.SampleDataUtil;
+import bizbook.storage.AddressBookStorage;
+import bizbook.storage.JsonAddressBookStorage;
+import bizbook.storage.JsonUserPrefsStorage;
+import bizbook.storage.Storage;
+import bizbook.storage.StorageManager;
+import bizbook.storage.UserPrefsStorage;
+import bizbook.ui.Ui;
+import bizbook.ui.UiManager;
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.DataLoadingException;
-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;
/**
* Runs the application.
diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/bizbook/commons/core/Config.java
similarity index 94%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/bizbook/commons/core/Config.java
index 485f85a5e05..2a357208d61 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/bizbook/commons/core/Config.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.logging.Level;
-import seedu.address.commons.util.ToStringBuilder;
+import bizbook.commons.util.ToStringBuilder;
/**
* Config values used by the app
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/bizbook/commons/core/GuiSettings.java
similarity index 96%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/bizbook/commons/core/GuiSettings.java
index a97a86ee8d7..ec6ee16a502 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/bizbook/commons/core/GuiSettings.java
@@ -1,10 +1,10 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
import java.awt.Point;
import java.io.Serializable;
import java.util.Objects;
-import seedu.address.commons.util.ToStringBuilder;
+import bizbook.commons.util.ToStringBuilder;
/**
* A Serializable class that contains the GUI settings.
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/bizbook/commons/core/LogsCenter.java
similarity index 99%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/bizbook/commons/core/LogsCenter.java
index 8cf8e15a0f0..8679301e887 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/bizbook/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/bizbook/commons/core/Version.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/bizbook/commons/core/Version.java
index 491d24559b4..98bc95a81e4 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/bizbook/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -50,6 +50,7 @@ public boolean isEarlyAccess() {
/**
* Parses a version number string in the format V1.2.3.
+ *
* @param versionString version number string
* @return a Version object
*/
diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/bizbook/commons/core/index/Index.java
similarity index 95%
rename from src/main/java/seedu/address/commons/core/index/Index.java
rename to src/main/java/bizbook/commons/core/index/Index.java
index dd170d8b68d..81ee3341cfc 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/bizbook/commons/core/index/Index.java
@@ -1,6 +1,6 @@
-package seedu.address.commons.core.index;
+package bizbook.commons.core.index;
-import seedu.address.commons.util.ToStringBuilder;
+import bizbook.commons.util.ToStringBuilder;
/**
* Represents a zero-based or one-based index.
diff --git a/src/main/java/seedu/address/commons/exceptions/DataLoadingException.java b/src/main/java/bizbook/commons/exceptions/DataLoadingException.java
similarity index 82%
rename from src/main/java/seedu/address/commons/exceptions/DataLoadingException.java
rename to src/main/java/bizbook/commons/exceptions/DataLoadingException.java
index 9904ba47afe..476fc6cb013 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataLoadingException.java
+++ b/src/main/java/bizbook/commons/exceptions/DataLoadingException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package bizbook.commons.exceptions;
/**
* Represents an error during loading of data from a file.
diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/bizbook/commons/exceptions/IllegalValueException.java
similarity index 93%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/bizbook/commons/exceptions/IllegalValueException.java
index 19124db485c..28ee01e6e83 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/bizbook/commons/exceptions/IllegalValueException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package bizbook.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/bizbook/commons/util/AppUtil.java
similarity index 94%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/bizbook/commons/util/AppUtil.java
index 87aa89c0326..270c4ca9412 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/bizbook/commons/util/AppUtil.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
import static java.util.Objects.requireNonNull;
+import bizbook.MainApp;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
/**
* A container for App specific utility functions
diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/bizbook/commons/util/CollectionUtil.java
similarity index 91%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/bizbook/commons/util/CollectionUtil.java
index eafe4dfd681..50a969362e9 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/bizbook/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
import static java.util.Objects.requireNonNull;
@@ -12,7 +12,9 @@
*/
public class CollectionUtil {
- /** @see #requireAllNonNull(Collection) */
+ /**
+ * @see #requireAllNonNull(Collection)
+ */
public static void requireAllNonNull(Object... items) {
requireNonNull(items);
Stream.of(items).forEach(Objects::requireNonNull);
diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/bizbook/commons/util/ConfigUtil.java
similarity index 77%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/bizbook/commons/util/ConfigUtil.java
index 7b829c3c4cc..cd978003ec9 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/bizbook/commons/util/ConfigUtil.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.util;
+package bizbook.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.DataLoadingException;
+import bizbook.commons.core.Config;
+import bizbook.commons.exceptions.DataLoadingException;
/**
* A class for accessing the Config File.
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/bizbook/commons/util/FileUtil.java
similarity index 98%
rename from src/main/java/seedu/address/commons/util/FileUtil.java
rename to src/main/java/bizbook/commons/util/FileUtil.java
index b1e2767cdd9..778b7e569b6 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/bizbook/commons/util/FileUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
import java.io.IOException;
import java.nio.file.Files;
@@ -20,6 +20,7 @@ public static boolean isFileExists(Path file) {
/**
* Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)},
* otherwise returns false.
+ *
* @param path A string representing the file path. Cannot be null.
*/
public static boolean isValidPath(String path) {
@@ -33,6 +34,7 @@ public static boolean isValidPath(String path) {
/**
* Creates a file if it does not exist along with its missing parent directories.
+ *
* @throws IOException if the file or directory cannot be created.
*/
public static void createIfMissing(Path file) throws IOException {
diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/bizbook/commons/util/JsonUtil.java
similarity index 86%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/bizbook/commons/util/JsonUtil.java
index 100cb16c395..aa14fa739ce 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/bizbook/commons/util/JsonUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
import static java.util.Objects.requireNonNull;
@@ -11,17 +11,20 @@
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataLoadingException;
+import bizbook.commons.core.LogsCenter;
+import bizbook.commons.exceptions.DataLoadingException;
/**
* Converts a Java object instance to JSON and vice versa
@@ -37,7 +40,8 @@ public class JsonUtil {
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.registerModule(new SimpleModule("SimpleModule")
.addSerializer(Level.class, new ToStringSerializer())
- .addDeserializer(Level.class, new LevelDeserializer(Level.class)));
+ .addDeserializer(Level.class, new LevelDeserializer(Level.class))
+ .addSerializer(Path.class, new PathSerializer(Path.class)));
static void serializeObjectToJsonFile(Path jsonFile, T objectToSerialize) throws IOException {
FileUtil.writeToFile(jsonFile, toJsonString(objectToSerialize));
@@ -80,6 +84,7 @@ public static Optional readJsonFile(
/**
* Saves the Json object to the specified file.
* Overwrites existing file if it exists, creates a new file if it doesn't.
+ *
* @param jsonFile cannot be null
* @param filePath cannot be null
* @throws IOException if there was an error during writing to the file
@@ -94,6 +99,7 @@ public static void saveJsonFile(T jsonFile, Path filePath) throws IOExceptio
/**
* Converts a given string representation of a JSON data to instance of a class
+ *
* @param The generic type to create an instance of
* @return The instance of T with the specified values in the JSON string
*/
@@ -103,6 +109,7 @@ public static T fromJsonString(String json, Class instanceClass) throws I
/**
* Converts a given instance of a class into its JSON data string representation
+ *
* @param instance The T object to be converted into the JSON string
* @param The generic type to create an instance of
* @return JSON data representation of the given class instance, in string
@@ -141,4 +148,17 @@ public Class handledType() {
}
}
+ /**
+ * Represents a class that can serialize to
+ */
+ private static class PathSerializer extends StdSerializer {
+ protected PathSerializer(Class t) {
+ super(t);
+ }
+
+ @Override
+ public void serialize(Path path, JsonGenerator generator, SerializerProvider provider) throws IOException {
+ generator.writeString(path.toString());
+ }
+ }
}
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/bizbook/commons/util/StringUtil.java
similarity index 95%
rename from src/main/java/seedu/address/commons/util/StringUtil.java
rename to src/main/java/bizbook/commons/util/StringUtil.java
index 61cc8c9a1cb..d48ac80fd76 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/bizbook/commons/util/StringUtil.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
+import static bizbook.commons.util.AppUtil.checkArgument;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -20,6 +20,7 @@ public class StringUtil {
* containsWordIgnoreCase("ABc def", "DEF") == true
* containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
*
+ *
* @param sentence cannot be null
* @param word cannot be null, cannot be empty, must be a single word
*/
@@ -53,6 +54,7 @@ public static String getDetails(Throwable t) {
* e.g. 1, 2, 3, ..., {@code Integer.MAX_VALUE}
* Will return false for any other non-null string input
* e.g. empty string, "-1", "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters)
+ *
* @throws NullPointerException if {@code s} is null.
*/
public static boolean isNonZeroUnsignedInteger(String s) {
diff --git a/src/main/java/seedu/address/commons/util/ToStringBuilder.java b/src/main/java/bizbook/commons/util/ToStringBuilder.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/ToStringBuilder.java
rename to src/main/java/bizbook/commons/util/ToStringBuilder.java
index d979b926734..b65c0910be2 100644
--- a/src/main/java/seedu/address/commons/util/ToStringBuilder.java
+++ b/src/main/java/bizbook/commons/util/ToStringBuilder.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
/**
* Builds a string representation of an object that is suitable as the return value of {@link Object#toString()}.
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/bizbook/logic/Logic.java
similarity index 62%
rename from src/main/java/seedu/address/logic/Logic.java
rename to src/main/java/bizbook/logic/Logic.java
index 92cd8fa605a..58c202e42b4 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/bizbook/logic/Logic.java
@@ -1,14 +1,16 @@
-package seedu.address.logic;
+package bizbook.logic;
import java.nio.file.Path;
+import bizbook.commons.core.GuiSettings;
+import bizbook.logic.commands.CommandResult;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.Model;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
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;
/**
* API of the Logic component
@@ -16,6 +18,7 @@
public interface Logic {
/**
* Executes the command and returns the result.
+ *
* @param commandText The command as entered by the user.
* @return the result of the command execution.
* @throws CommandException If an error occurs during command execution.
@@ -26,13 +29,16 @@ public interface Logic {
/**
* Returns the AddressBook.
*
- * @see seedu.address.model.Model#getAddressBook()
+ * @see Model#getAddressBook()
*/
ReadOnlyAddressBook getAddressBook();
/** Returns an unmodifiable view of the filtered list of persons */
ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the list of pinned persons */
+ ObservableList getPinnedPersonList();
+
/**
* Returns the user prefs' address book file path.
*/
@@ -43,6 +49,11 @@ public interface Logic {
*/
GuiSettings getGuiSettings();
+ /**
+ * Returns the person who will be focused on.
+ */
+ ObjectProperty getFocusedPerson();
+
/**
* Set the user prefs' GUI settings.
*/
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/bizbook/logic/LogicManager.java
similarity index 74%
rename from src/main/java/seedu/address/logic/LogicManager.java
rename to src/main/java/bizbook/logic/LogicManager.java
index 5aa3b91c7d0..47b6d2dc6dc 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/bizbook/logic/LogicManager.java
@@ -1,22 +1,23 @@
-package seedu.address.logic;
+package bizbook.logic;
import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.Path;
import java.util.logging.Logger;
+import bizbook.commons.core.GuiSettings;
+import bizbook.commons.core.LogsCenter;
+import bizbook.logic.commands.Command;
+import bizbook.logic.commands.CommandResult;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.AddressBookParser;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.Model;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.person.Person;
+import bizbook.storage.Storage;
+import javafx.beans.property.ObjectProperty;
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;
/**
* The main LogicManager of the app.
@@ -49,6 +50,7 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
CommandResult commandResult;
Command command = addressBookParser.parseCommand(commandText);
commandResult = command.execute(model);
+ model.saveAddressBookVersion();
try {
storage.saveAddressBook(model.getAddressBook());
@@ -71,6 +73,11 @@ public ObservableList getFilteredPersonList() {
return model.getFilteredPersonList();
}
+ @Override
+ public ObservableList getPinnedPersonList() {
+ return model.getPinnedPersonList();
+ }
+
@Override
public Path getAddressBookFilePath() {
return model.getAddressBookFilePath();
@@ -81,6 +88,11 @@ public GuiSettings getGuiSettings() {
return model.getGuiSettings();
}
+ @Override
+ public ObjectProperty getFocusedPerson() {
+ return model.getFocusedPerson();
+ }
+
@Override
public void setGuiSettings(GuiSettings guiSettings) {
model.setGuiSettings(guiSettings);
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/bizbook/logic/Messages.java
similarity index 61%
rename from src/main/java/seedu/address/logic/Messages.java
rename to src/main/java/bizbook/logic/Messages.java
index ecd32c31b53..6ef559529ab 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/bizbook/logic/Messages.java
@@ -1,23 +1,26 @@
-package seedu.address.logic;
+package bizbook.logic;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import seedu.address.logic.parser.Prefix;
-import seedu.address.model.person.Person;
+import bizbook.logic.parser.Prefix;
+import bizbook.model.person.Person;
/**
* Container for user visible messages.
*/
public class Messages {
- public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
+ 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_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid.";
+ public static final String MESSAGE_INVALID_NOTE_INDEX = "The note index provided is invalid.";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
+ public static final String MESSAGE_UNSUPPORTED_FILE_TYPE = "This file type is not supported. \n%1$s";
+ public static final String MESSAGE_INVALID_FILE_PATH = "The following file path is invalid: %1$s";
/**
* Returns an error message indicating the duplicate prefixes.
@@ -32,7 +35,7 @@ public static String getErrorMessageForDuplicatePrefixes(Prefix... duplicatePref
}
/**
- * Formats the {@code person} for display to the user.
+ * Formats contact detail of {@code person} for display to the user.
*/
public static String format(Person person) {
final StringBuilder builder = new StringBuilder();
@@ -45,6 +48,21 @@ public static String format(Person person) {
.append(person.getAddress())
.append("; Tags: ");
person.getTags().forEach(builder::append);
+
+ builder.append("; Notes: ");
+ person.getNotes().forEach(builder::append);
+
+ return builder.toString();
+ }
+
+ /**
+ * Formats contact detail of {@code person} to display only name and phone
+ * to the user.
+ */
+ public static String formatShort(Person person) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(person.getName())
+ .append(String.format(" (%s)", person.getPhone()));
return builder.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/bizbook/logic/commands/AddCommand.java
similarity index 78%
rename from src/main/java/seedu/address/logic/commands/AddCommand.java
rename to src/main/java/bizbook/logic/commands/AddCommand.java
index 5d7185a9680..875be726169 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/bizbook/logic/commands/AddCommand.java
@@ -1,17 +1,17 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
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.commons.util.ToStringBuilder;
-import seedu.address.logic.Messages;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
/**
* Adds a person to the address book.
diff --git a/src/main/java/bizbook/logic/commands/AddNoteCommand.java b/src/main/java/bizbook/logic/commands/AddNoteCommand.java
new file mode 100644
index 00000000000..a0bb1a73499
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/AddNoteCommand.java
@@ -0,0 +1,106 @@
+package bizbook.logic.commands;
+
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
+import static bizbook.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+
+
+/**
+ * Changes or adds the notes of an existing person in BizBook.
+ */
+public class AddNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "addnote";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Adds the note of the person identified "
+ + "by the person index number used on the left display panel. "
+ + "New note(letters and numbers) will be appended to the notes currently stored.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "n/NOTE\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + "n/High profile client.";
+
+ public static final String MESSAGE_ADD_NOTE_SUCCESS = "Added note to Person: %1$s";
+ public static final String DUPLICATE_MESSAGE_CONSTRAINTS = "There is already an existing note with this name.";
+
+ private final Index index;
+ private final Note note;
+
+
+ /**
+ * @param index of the person in the filtered person list to add a new note
+ * @param note of the person to be added
+ */
+ public AddNoteCommand(Index index, Note note) {
+ requireAllNonNull(index, note);
+
+ this.index = index;
+ this.note = note;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(index.getZeroBased());
+
+ ArrayList notesList = new ArrayList<>(personToEdit.getNotes());
+
+ if (notesList.contains(note)) {
+ throw new CommandException(DUPLICATE_MESSAGE_CONSTRAINTS);
+ }
+
+ notesList.add(note);
+
+ Person editedPerson = new Person(
+ personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(),
+ personToEdit.getAddress(), personToEdit.getTags(), notesList);
+
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+
+ model.getFocusedPerson().set(editedPerson);
+
+ return new CommandResult(String.format(generateSuccessMessage(editedPerson), index.getOneBased()),
+ false, false);
+ }
+
+ /**
+ * Generates a command execution success message
+ * the remark is added to or removed from
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+ return String.format(MESSAGE_ADD_NOTE_SUCCESS, Messages.format(personToEdit));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddNoteCommand)) {
+ return false;
+ }
+
+ AddNoteCommand otherAddNoteCommand = (AddNoteCommand) other;
+ return note.equals(otherAddNoteCommand.note);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/bizbook/logic/commands/ClearCommand.java
similarity index 50%
rename from src/main/java/seedu/address/logic/commands/ClearCommand.java
rename to src/main/java/bizbook/logic/commands/ClearCommand.java
index 9c86b1fa6e4..f42d876f319 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/bizbook/logic/commands/ClearCommand.java
@@ -1,16 +1,19 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
import static java.util.Objects.requireNonNull;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
/**
* Clears the address book.
*/
public class ClearCommand extends Command {
-
public static final String COMMAND_WORD = "clear";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes all contacts.\n"
+ + "Parameters: None\n"
+ + "Example: " + COMMAND_WORD;
public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
@@ -18,6 +21,8 @@ public class ClearCommand extends Command {
public CommandResult execute(Model model) {
requireNonNull(model);
model.setAddressBook(new AddressBook());
- return new CommandResult(MESSAGE_SUCCESS);
+ model.setFocusPerson(null);
+ CommandResult commandResult = new CommandResult(MESSAGE_SUCCESS);
+ return commandResult;
}
}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/bizbook/logic/commands/Command.java
similarity index 78%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/bizbook/logic/commands/Command.java
index 64f18992160..894f249f3da 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/bizbook/logic/commands/Command.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.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/bizbook/logic/commands/CommandResult.java
similarity index 75%
rename from src/main/java/seedu/address/logic/commands/CommandResult.java
rename to src/main/java/bizbook/logic/commands/CommandResult.java
index 249b6072d0d..d1c1237bc16 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/bizbook/logic/commands/CommandResult.java
@@ -1,10 +1,10 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
import static java.util.Objects.requireNonNull;
import java.util.Objects;
-import seedu.address.commons.util.ToStringBuilder;
+import bizbook.commons.util.ToStringBuilder;
/**
* Represents the result of a command execution.
@@ -19,6 +19,9 @@ public class CommandResult {
/** The application should exit. */
private final boolean exit;
+ /** The application should toggle its theme. */
+ private final boolean themeChange;
+
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
@@ -26,6 +29,17 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
+ this.themeChange = false;
+ }
+
+ /**
+ * Constructs a {@code CommandResult} with the specified fields.
+ */
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean themeChange) {
+ this.feedbackToUser = requireNonNull(feedbackToUser);
+ this.showHelp = showHelp;
+ this.exit = exit;
+ this.themeChange = themeChange;
}
/**
@@ -48,6 +62,10 @@ public boolean isExit() {
return exit;
}
+ public boolean isThemeChange() {
+ return themeChange;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -78,5 +96,4 @@ public String toString() {
.add("exit", exit)
.toString();
}
-
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/bizbook/logic/commands/DeleteCommand.java
similarity index 72%
rename from src/main/java/seedu/address/logic/commands/DeleteCommand.java
rename to src/main/java/bizbook/logic/commands/DeleteCommand.java
index 1135ac19b74..e6ff3130e67 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/bizbook/logic/commands/DeleteCommand.java
@@ -1,15 +1,15 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
import static java.util.Objects.requireNonNull;
import java.util.List;
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.logic.Messages;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import bizbook.commons.core.index.Index;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
/**
* Deletes a person identified using it's displayed index from the address book.
@@ -27,6 +27,11 @@ public class DeleteCommand extends Command {
private final Index targetIndex;
+ /**
+ * Creates a DeleteCommand to delete the specified person.
+ *
+ * @param targetIndex of the person in the filtered person list to be deleted
+ */
public DeleteCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}
@@ -42,7 +47,12 @@ public CommandResult execute(Model model) throws CommandException {
Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
+
+ model.updateFocusPerson(personToDelete, null);
+
+ CommandResult commandResult = new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS,
+ Messages.formatShort(personToDelete)));
+ return commandResult;
}
@Override
diff --git a/src/main/java/bizbook/logic/commands/DeleteNoteCommand.java b/src/main/java/bizbook/logic/commands/DeleteNoteCommand.java
new file mode 100644
index 00000000000..735d99fd068
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/DeleteNoteCommand.java
@@ -0,0 +1,115 @@
+package bizbook.logic.commands;
+
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
+import static bizbook.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
+
+/**
+ * Deletes note of an existing person in the address book.
+ */
+public class DeleteNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletenote";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the note of the person identified "
+ + "by the index number used in the person listing and the index of the note.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "i/NOTE_INDEX\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + "i/1";
+
+ public static final String MESSAGE_DELETE_NOTE_SUCCESS = "Deleted note of Person: %1$s";
+
+ /**
+ * Index of the person whose note is to be deleted
+ */
+ private final Index index;
+
+ /**
+ * Index of the note be deleted
+ */
+ private final Index noteIndex;
+
+ /**
+ * @param index of the person in the filtered person list to edit the notes
+ * @param noteIndex of the note to be deleted
+ */
+ public DeleteNoteCommand(Index index, Index noteIndex) {
+ requireAllNonNull(index, noteIndex);
+
+ this.index = index;
+ this.noteIndex = noteIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(index.getZeroBased());
+
+ List notesList = new ArrayList<>(personToEdit.getNotes());
+
+ // if there are no notes with this index
+ if (noteIndex.getOneBased() > notesList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_NOTE_INDEX);
+ }
+
+ // remove the specified note
+ Note noteToRemove = notesList.get(noteIndex.getZeroBased());
+ notesList.remove(noteToRemove);
+
+ ArrayList updatedNotesList = new ArrayList<>(notesList);
+
+ Person editedPerson = new Person(
+ personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(),
+ personToEdit.getAddress(), personToEdit.getTags(), updatedNotesList);
+
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+
+ ObjectProperty focusedPerson = model.getFocusedPerson();
+ focusedPerson.set(editedPerson);
+
+ return new CommandResult(String.format(generateSuccessMessage(editedPerson), index.getOneBased()),
+ false, false);
+ }
+
+ /**
+ * Generates a command execution success message
+ * the remark is added to or removed from
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+ return String.format(MESSAGE_DELETE_NOTE_SUCCESS, Messages.format(personToEdit));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteNoteCommand)) {
+ return false;
+ }
+
+ DeleteNoteCommand otherDeleteNoteCommand = (DeleteNoteCommand) other;
+ return index.equals(otherDeleteNoteCommand.index) && noteIndex.equals(otherDeleteNoteCommand.noteIndex);
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/DeleteTagCommand.java b/src/main/java/bizbook/logic/commands/DeleteTagCommand.java
new file mode 100644
index 00000000000..dad23c010b6
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/DeleteTagCommand.java
@@ -0,0 +1,102 @@
+package bizbook.logic.commands;
+
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
+
+/**
+ * Delete a tag from an existing person in the address book.
+ */
+public class DeleteTagCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletetag";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the tag from a specfic person.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_TAG + "TAG\n"
+ + "Example: " + COMMAND_WORD + " 1 " + PREFIX_TAG + "BusinessMan";
+
+ public static final String MESSAGE_REMOVE_TAG_SUCCESS = "Tag was removed from Person: %1$s";
+ public static final String TAG_DOES_NOT_EXIST = "Unable to delete tag named %1$s "
+ + "because the tag does not exist for the person.";
+
+ private final Index personIndex;
+ private final Tag tagToDelete;
+
+ /**
+ * @param personIndex of the person in the filtered person list to remove the tag from.
+ * @param tag is the name of the tag to be removed from the {@code Person}.
+ */
+ public DeleteTagCommand(Index personIndex, Tag tag) {
+ requireAllNonNull(personIndex, tag);
+
+ this.personIndex = personIndex;
+ this.tagToDelete = tag;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+
+ List lastShownList = model.getFilteredPersonList();
+
+ if (personIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(personIndex.getZeroBased());
+ Set tagSet = personToEdit.getTags();
+
+ if (!tagSet.contains(tagToDelete)) {
+ throw new CommandException(String.format(TAG_DOES_NOT_EXIST, tagToDelete.tagName));
+ }
+
+ Set updatedTagSet = tagSet.stream()
+ .filter(t -> !t.equals(tagToDelete))
+ .collect(Collectors.toSet());
+
+ Name name = personToEdit.getName();
+ Email email = personToEdit.getEmail();
+ Phone phone = personToEdit.getPhone();
+ Address address = personToEdit.getAddress();
+ ArrayList notesList = personToEdit.getNotes();
+
+ Person updatedPerson = new Person(name, phone, email, address, updatedTagSet, notesList);
+
+ model.setPerson(personToEdit, updatedPerson);
+
+ return new CommandResult(String.format(MESSAGE_REMOVE_TAG_SUCCESS, Messages.format(updatedPerson)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof DeleteTagCommand)) {
+ return false;
+ }
+
+ DeleteTagCommand otherDeleteTagCommand = (DeleteTagCommand) other;
+ return this.personIndex.equals(otherDeleteTagCommand.personIndex)
+ && this.tagToDelete.equals(otherDeleteTagCommand.tagToDelete);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/bizbook/logic/commands/EditCommand.java
similarity index 83%
rename from src/main/java/seedu/address/logic/commands/EditCommand.java
rename to src/main/java/bizbook/logic/commands/EditCommand.java
index 4b581c7331e..c9efbe2eed4 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/bizbook/logic/commands/EditCommand.java
@@ -1,32 +1,34 @@
-package seedu.address.logic.commands;
-
+package bizbook.logic.commands;
+
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static bizbook.model.Model.PREDICATE_SHOW_ALL_PERSONS;
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.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.CollectionUtil;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.logic.Messages;
-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;
+import bizbook.commons.core.index.Index;
+import bizbook.commons.util.CollectionUtil;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
/**
* Edits the details of an existing person in the address book.
@@ -83,6 +85,8 @@ public CommandResult execute(Model model) throws CommandException {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}
+ model.updateFocusPerson(personToEdit, editedPerson);
+
model.setPerson(personToEdit, editedPerson);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
@@ -100,8 +104,9 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript
Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
+ ArrayList updatedNotes = editPersonDescriptor.getNotes().orElse(personToEdit.getNotes());
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags, updatedNotes);
}
@Override
@@ -138,6 +143,7 @@ public static class EditPersonDescriptor {
private Email email;
private Address address;
private Set tags;
+ private ArrayList notes;
public EditPersonDescriptor() {}
@@ -151,6 +157,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) {
setEmail(toCopy.email);
setAddress(toCopy.address);
setTags(toCopy.tags);
+ setNotes(toCopy.notes);
}
/**
@@ -192,12 +199,20 @@ public Optional getAddress() {
return Optional.ofNullable(address);
}
+ public void setNotes(ArrayList notes) {
+ this.notes = (notes != null) ? new ArrayList<>(notes) : null;
+ }
+
+ public Optional> getNotes() {
+ return (notes != null) ? Optional.of(notes) : Optional.empty();
+ }
+
/**
* 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;
+ this.tags = (tags != null) ? new LinkedHashSet<>(tags) : null;
}
/**
diff --git a/src/main/java/bizbook/logic/commands/EditNoteCommand.java b/src/main/java/bizbook/logic/commands/EditNoteCommand.java
new file mode 100644
index 00000000000..46ab5d881d8
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/EditNoteCommand.java
@@ -0,0 +1,117 @@
+package bizbook.logic.commands;
+
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
+import static bizbook.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+
+/**
+ * Edits a note of an existing person in the address book.
+ */
+public class EditNoteCommand extends Command {
+
+ public static final String COMMAND_WORD = "editnote";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Edits the note of the person identified "
+ + "by the person index number used on the left display panel. "
+ + "The note will replace the currently stored note at the specified index.\n"
+ + "Parameters: INDEX i/NOTE_INDEX n/NOTE\n"
+ + "Example: " + COMMAND_WORD + " 1 i/1 n/High profile client.";
+
+ public static final String MESSAGE_EDIT_NOTE_SUCCESS = "Edit note of Person: %1$s";
+ public static final String DUPLICATE_MESSAGE_CONSTRAINTS = "There is already an existing note with this name.";
+
+ private final Index personIndex;
+ private final Index noteIndex;
+ private final Note note;
+
+ /**
+ * @param personIndex of the person in the filtered person list to edit the note
+ * @param noteIndex of the person in the filtered person list to edit the note
+ * @param note of the person to be updated to
+ */
+ public EditNoteCommand(Index personIndex, Index noteIndex, Note note) {
+ requireAllNonNull(personIndex, note, noteIndex);
+
+ this.personIndex = personIndex;
+ this.noteIndex = noteIndex;
+ this.note = note;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPersonList();
+
+ if (personIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToEdit = lastShownList.get(personIndex.getZeroBased());
+
+ ArrayList notesList = new ArrayList<>(personToEdit.getNotes());
+
+ if (notesList.contains(note)) {
+ throw new CommandException(DUPLICATE_MESSAGE_CONSTRAINTS);
+ } else if (noteIndex.getZeroBased() >= notesList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_NOTE_INDEX);
+ }
+
+ Person editedPerson = updateNote(personToEdit, notesList);
+
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+
+ model.getFocusedPerson().set(editedPerson);
+
+ return new CommandResult(String.format(generateSuccessMessage(editedPerson), personIndex.getOneBased()),
+ false, false);
+ }
+
+ /**
+ * Generates a command execution success message the remark is added to or removed from
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+ return String.format(MESSAGE_EDIT_NOTE_SUCCESS, Messages.format(personToEdit));
+ }
+
+ /**
+ * Updates the notes of the given person with the given note
+ * {@code personToEdit, notesToEdit}.
+ */
+ private Person updateNote(Person personToEdit, ArrayList notesToEdit) {
+ // Convert Set to List for indexed access
+ List notesList = new ArrayList<>(notesToEdit);
+ notesList.set(noteIndex.getZeroBased(), note);
+ ArrayList editedNotes = new ArrayList<>(notesList);
+
+ return new Person(personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(),
+ personToEdit.getAddress(), personToEdit.getTags(), editedNotes);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditNoteCommand otherEditNotesCommand)) {
+ return false;
+ }
+
+ return personIndex.equals(otherEditNotesCommand.personIndex)
+ && noteIndex.equals(otherEditNotesCommand.noteIndex)
+ && note.equals(otherEditNotesCommand.note);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/bizbook/logic/commands/ExitCommand.java
similarity index 62%
rename from src/main/java/seedu/address/logic/commands/ExitCommand.java
rename to src/main/java/bizbook/logic/commands/ExitCommand.java
index 3dd85a8ba90..121163dbf49 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/bizbook/logic/commands/ExitCommand.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import seedu.address.model.Model;
+import bizbook.model.Model;
/**
* Terminates the program.
@@ -8,6 +8,10 @@
public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Exits the app.\n"
+ + "Parameters: None\n"
+ + "Example: " + COMMAND_WORD;
public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
diff --git a/src/main/java/bizbook/logic/commands/ExportCommand.java b/src/main/java/bizbook/logic/commands/ExportCommand.java
new file mode 100644
index 00000000000..b161fd07229
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/ExportCommand.java
@@ -0,0 +1,78 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.parser.CliSyntax.PREFIX_FILE;
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.commands.exporter.Exporter;
+import bizbook.logic.commands.exporter.FileType;
+import bizbook.logic.commands.exporter.exceptions.InvalidAddressBookException;
+import bizbook.model.Model;
+
+/**
+ * Exports contact list to a csv file.
+ */
+public class ExportCommand extends Command {
+
+ public static final String COMMAND_WORD = "export";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Exports the whole contact list "
+ + "to a specified file type. Only CSV and VCF are supported.\n"
+ + "Parameters: " + PREFIX_FILE + "FILETYPE\n"
+ + "Example: " + COMMAND_WORD + " " + PREFIX_FILE + "csv";
+
+ public static final String MESSAGE_SUCCESS = "Contact list successfully exported to a %1$s file";
+ public static final String MESSAGE_FAILED_TO_SAVE = "Unable to export contact list to a %1$s file"
+ + ", please ensure that the file is closed before exporting";
+
+ private final FileType fileType;
+
+ /**
+ * Creates an ExportCsvCommand.
+ *
+ * @param fileType to export the data into.
+ */
+ public ExportCommand(FileType fileType) {
+ requireNonNull(fileType);
+ this.fileType = fileType;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ try {
+ Exporter exporter = fileType.exporter(model.getUserPrefs());
+ exporter.exportAddressBook(model.getAddressBook());
+ } catch (IOException io) {
+ throw new CommandException(String.format(MESSAGE_FAILED_TO_SAVE, fileType));
+ } catch (InvalidAddressBookException iabe) {
+ throw new CommandException(iabe.getMessage());
+ }
+
+ return new CommandResult(String.format(MESSAGE_SUCCESS, fileType));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ExportCommand)) {
+ return false;
+ }
+
+ ExportCommand otherExportCommand = (ExportCommand) other;
+ return fileType.equals(otherExportCommand.fileType);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("fileType", fileType)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/bizbook/logic/commands/FindCommand.java
similarity index 87%
rename from src/main/java/seedu/address/logic/commands/FindCommand.java
rename to src/main/java/bizbook/logic/commands/FindCommand.java
index 72b9eddd3a7..80268066a72 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/bizbook/logic/commands/FindCommand.java
@@ -1,11 +1,11 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
import static java.util.Objects.requireNonNull;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.logic.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.model.Model;
+import bizbook.model.person.NameContainsKeywordsPredicate;
/**
* Finds and lists all persons in address book whose name contains any of the argument keywords.
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/bizbook/logic/commands/HelpCommand.java
similarity index 88%
rename from src/main/java/seedu/address/logic/commands/HelpCommand.java
rename to src/main/java/bizbook/logic/commands/HelpCommand.java
index bf824f91bd0..5414a378dfc 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/bizbook/logic/commands/HelpCommand.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import seedu.address.model.Model;
+import bizbook.model.Model;
/**
* Format full help instructions for every command for display.
diff --git a/src/main/java/bizbook/logic/commands/ImportCommand.java b/src/main/java/bizbook/logic/commands/ImportCommand.java
new file mode 100644
index 00000000000..2ae359a0a18
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/ImportCommand.java
@@ -0,0 +1,89 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.parser.CliSyntax.PREFIX_FILE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PATH;
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.commands.exporter.FileType;
+import bizbook.logic.commands.exporter.Importer;
+import bizbook.logic.commands.exporter.exceptions.InvalidFileException;
+import bizbook.model.Model;
+
+/**
+ * Imports contact list to a csv file.
+ */
+public class ImportCommand extends Command {
+
+ public static final String COMMAND_WORD = "import";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Imports contacts from a file into the address book."
+ + " Only VCF is supported.\n"
+ + "Parameters: " + PREFIX_FILE + "FILETYPE " + PREFIX_PATH + "PATH\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_FILE + "vcf "
+ + PREFIX_PATH + "./path/to/contacts.vcf";
+
+ public static final String MESSAGE_SUCCESS = "%1$d contacts were successfully imported from file";
+ public static final String MESSAGE_FAILED_TO_LOAD = "Unable to find or load the file to import the contact list";
+
+ private final FileType fileType;
+ private final Path path;
+
+ /**
+ * Creates an ImportCommand.
+ *
+ * @param fileType of the file at the path.
+ * @param path to import the data from.
+ */
+ public ImportCommand(FileType fileType, Path path) {
+ requireNonNull(fileType);
+ requireNonNull(path);
+
+ this.fileType = fileType;
+ this.path = path;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ try {
+ Importer importer = fileType.importer();
+ model.setAddressBook(importer.importAddressBook(path));
+ } catch (IOException io) {
+ throw new CommandException(String.format(MESSAGE_FAILED_TO_LOAD));
+ } catch (InvalidFileException ife) {
+ throw new CommandException(ife.getMessage());
+ }
+
+ int numContacts = model.getAddressBook().getPersonList().size();
+ return new CommandResult(String.format(MESSAGE_SUCCESS, numContacts));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ImportCommand)) {
+ return false;
+ }
+
+ ImportCommand otherExportCommand = (ImportCommand) other;
+ return fileType.equals(otherExportCommand.fileType)
+ && path.equals(otherExportCommand.path);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("fileType", fileType)
+ .add("path", path)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/bizbook/logic/commands/ListCommand.java
similarity index 60%
rename from src/main/java/seedu/address/logic/commands/ListCommand.java
rename to src/main/java/bizbook/logic/commands/ListCommand.java
index 84be6ad2596..6d29f41a5d3 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/bizbook/logic/commands/ListCommand.java
@@ -1,9 +1,9 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
+import static bizbook.model.Model.PREDICATE_SHOW_ALL_PERSONS;
import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-import seedu.address.model.Model;
+import bizbook.model.Model;
/**
* Lists all persons in the address book to the user.
@@ -11,6 +11,10 @@
public class ListCommand extends Command {
public static final String COMMAND_WORD = "list";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Shows a list of all persons in the address book.\n"
+ + "Parameters: None\n"
+ + "Example: " + COMMAND_WORD;
public static final String MESSAGE_SUCCESS = "Listed all persons";
diff --git a/src/main/java/bizbook/logic/commands/PinCommand.java b/src/main/java/bizbook/logic/commands/PinCommand.java
new file mode 100644
index 00000000000..fde2bc9486a
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/PinCommand.java
@@ -0,0 +1,81 @@
+package bizbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
+
+/**
+ * Pins a person in address book to a pinned list.
+ */
+public class PinCommand extends Command {
+ public static final String COMMAND_WORD = "pin";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Pins the person identified by the index number.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_PIN_PERSON_SUCCESS = "Pinned Person: %1$s";
+ public static final String MESSAGE_ALREADY_PINNED = "This person already pinned";
+
+ private final Index targetIndex;
+
+ /**
+ * Creates a PinCommand to pin the specified person.
+ *
+ * @param targetIndex of the person in the filtered person list to be pinned
+ */
+ public PinCommand(Index targetIndex) {
+ assert targetIndex != null;
+ 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 personToPin = lastShownList.get(targetIndex.getZeroBased());
+
+ if (model.isPinned(personToPin)) {
+ throw new CommandException(MESSAGE_ALREADY_PINNED);
+ }
+
+ model.pinPerson(personToPin);
+ CommandResult commandResult = new CommandResult(String.format(MESSAGE_PIN_PERSON_SUCCESS,
+ Messages.formatShort(personToPin)), false, false);
+ return commandResult;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PinCommand)) {
+ return false;
+ }
+
+ PinCommand otherPinCommand = (PinCommand) other;
+ return targetIndex.equals(otherPinCommand.targetIndex);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("targetIndex", targetIndex)
+ .toString();
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/RedoCommand.java b/src/main/java/bizbook/logic/commands/RedoCommand.java
new file mode 100644
index 00000000000..bce48293606
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/RedoCommand.java
@@ -0,0 +1,43 @@
+package bizbook.logic.commands;
+
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+
+/**
+ * Reverts the changes made by the undo function.
+ */
+public class RedoCommand extends Command {
+ public static final String COMMAND_WORD = "redo";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Redoes the previous undo command that was executed.\n"
+ + "Parameters: None\n"
+ + "Example: " + COMMAND_WORD;
+
+ public static final String MESSAGE_REDO_SUCCESS = "Changes has been reverted!";
+ public static final String MESSAGE_REDO_FAILURE = "Unable revert changes because "
+ + "there is no newer version to revert to!";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+
+ if (!model.canRedo()) {
+ throw new CommandException(MESSAGE_REDO_FAILURE);
+ }
+
+ model.setFocusPerson(null);
+ model.redoAddressBookVersion();
+ return new CommandResult(MESSAGE_REDO_SUCCESS);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof RedoCommand)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/ToggleCommand.java b/src/main/java/bizbook/logic/commands/ToggleCommand.java
new file mode 100644
index 00000000000..fd5ba176e87
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/ToggleCommand.java
@@ -0,0 +1,41 @@
+package bizbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+
+/**
+ * Toggle system between light and dark mode.
+ */
+public class ToggleCommand extends Command {
+
+ public static final String COMMAND_WORD = "toggle";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Toggles between "
+ + "light mode and dark mode.\n"
+ + "Parameters: None\n"
+ + "Example: " + COMMAND_WORD;
+
+ public static final String MESSAGE_TOGGLE_SUCCESS = "Toggled theme successfully!";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ return new CommandResult(MESSAGE_TOGGLE_SUCCESS, false, false, true);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ToggleCommand)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/UndoCommand.java b/src/main/java/bizbook/logic/commands/UndoCommand.java
new file mode 100644
index 00000000000..59dc01c1078
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/UndoCommand.java
@@ -0,0 +1,45 @@
+package bizbook.logic.commands;
+
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+
+/**
+ * Reverts the changes made to the address book.
+ */
+public class UndoCommand extends Command {
+
+ public static final String COMMAND_WORD = "undo";
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Undoes the previous command that was executed.\n"
+ + "Parameters: None\n"
+ + "Example: " + COMMAND_WORD;
+
+ public static final String MESSAGE_UNDO_SUCCESS = "Changes has been reverted!";
+ public static final String MESSAGE_UNDO_FAILURE = "Unable revert changes because "
+ + "there is no older version to revert to!";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+
+ if (!model.canUndo()) {
+ throw new CommandException(MESSAGE_UNDO_FAILURE);
+ }
+
+ model.setFocusPerson(null);
+ model.revertAddressBookVersion();
+ return new CommandResult(MESSAGE_UNDO_SUCCESS);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UndoCommand)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/UnpinCommand.java b/src/main/java/bizbook/logic/commands/UnpinCommand.java
new file mode 100644
index 00000000000..16aba22d33b
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/UnpinCommand.java
@@ -0,0 +1,74 @@
+package bizbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
+
+/**
+ * Unpins a person in pinned list.
+ */
+public class UnpinCommand extends Command {
+ public static final String COMMAND_WORD = "unpin";
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Unpins the person identified by the index number.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_UNPIN_PERSON_SUCCESS = "Unpinned Person: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Creates a Unpin Command to unpin the specified person.
+ *
+ * @param targetIndex of the person in the pinned person list.
+ */
+ public UnpinCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getPinnedPersonList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToUnpin = lastShownList.get(targetIndex.getZeroBased());
+
+ model.unpinPerson(personToUnpin);
+ CommandResult commandResult = new CommandResult(String.format(MESSAGE_UNPIN_PERSON_SUCCESS,
+ Messages.formatShort(personToUnpin)), false, false);
+ return commandResult;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UnpinCommand)) {
+ return false;
+ }
+
+ UnpinCommand otherUnpinCommand = (UnpinCommand) other;
+ return targetIndex.equals(otherUnpinCommand.targetIndex);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("targetIndex", targetIndex)
+ .toString();
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/ViewCommand.java b/src/main/java/bizbook/logic/commands/ViewCommand.java
new file mode 100644
index 00000000000..82809522df3
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/ViewCommand.java
@@ -0,0 +1,72 @@
+package bizbook.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
+
+/**
+ * Views the details of a specfied person using it's displayed index from the address book.
+ */
+public class ViewCommand extends Command {
+
+ public static final String COMMAND_WORD = "view";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": View more details of "
+ + "a particular person in the contact list.\n"
+ + "Parameters: INDEX (Must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_VIEW_PERSON_SUCCESS = "Fetched details of person: %1$s";
+
+ private final Index targetIndex;
+
+ public ViewCommand(Index index) {
+ this.targetIndex = index;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List personList = model.getFilteredPersonList();
+
+ if (targetIndex.getZeroBased() >= personList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person person = personList.get(targetIndex.getZeroBased());
+ model.setFocusPerson(person);
+
+ return new CommandResult(String.format(MESSAGE_VIEW_PERSON_SUCCESS, targetIndex.getOneBased()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ViewCommand)) {
+ return false;
+ }
+
+ ViewCommand otherViewCommand = (ViewCommand) other;
+ return this.targetIndex.equals(otherViewCommand.targetIndex);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("targetIndex", targetIndex)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/bizbook/logic/commands/exceptions/CommandException.java
similarity index 89%
rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
rename to src/main/java/bizbook/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..25e1230cdb7 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/bizbook/logic/commands/exceptions/CommandException.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands.exceptions;
+package bizbook.logic.commands.exceptions;
/**
* Represents an error which occurs during execution of a {@link Command}.
diff --git a/src/main/java/bizbook/logic/commands/exporter/CsvExporter.java b/src/main/java/bizbook/logic/commands/exporter/CsvExporter.java
new file mode 100644
index 00000000000..e6f1f958aa6
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/CsvExporter.java
@@ -0,0 +1,83 @@
+package bizbook.logic.commands.exporter;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+import bizbook.commons.util.FileUtil;
+import bizbook.logic.commands.exporter.exceptions.InvalidAddressBookException;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+
+/**
+ * Represents a class that can export to CSV
+ */
+public class CsvExporter implements Exporter {
+ private static final String CSV_HEADERS = "Name,Phone No,Email,Address,Tags,Notes";
+
+ private final Path exportSubPath = Paths.get("bizbook.csv");
+ private final ReadOnlyUserPrefs userPrefs;
+
+ /**
+ * Constructs a {@code VcfExporter} class configured with {@code UserPrefs}
+ */
+ public CsvExporter(ReadOnlyUserPrefs userPrefs) {
+ this.userPrefs = userPrefs;
+ }
+
+ @Override
+ public void exportAddressBook(ReadOnlyAddressBook addressBook) throws IOException, InvalidAddressBookException {
+ if (addressBook.getPersonList().isEmpty()) {
+ throw new InvalidAddressBookException(MESSAGE_EMPTY_ADDRESS_BOOK);
+ }
+
+ Path exportPath = getExportPath();
+ FileUtil.createIfMissing(exportPath);
+
+ StringJoiner sj = new StringJoiner(System.lineSeparator());
+ sj.add(CSV_HEADERS);
+
+ addressBook.getPersonList()
+ .forEach(person -> sj.add(convertToCsv(person)));
+
+ FileUtil.writeToFile(exportPath, sj + System.lineSeparator());
+ }
+
+ /**
+ * Converts a {@code Person} object into csv format.
+ *
+ * @param person to be encoded into a csv format.
+ * @return A csv representation of the {@Code Person} object.
+ */
+ private String convertToCsv(Person person) {
+ StringJoiner sj = new StringJoiner(",");
+
+ sj.add(person.getName().fullName);
+ sj.add(person.getPhone().value);
+ sj.add(person.getEmail().value);
+
+ // Prevent excel from separating entries due to commas
+ String address = "\"" + person.getAddress().value + "\"";
+ sj.add(address);
+
+ String tags = person.getTags().stream()
+ .map(tag -> tag.tagName).collect(Collectors.joining(","));
+
+ String notes = person.getNotes().stream()
+ .map(Note::getNote).collect(Collectors.joining(","));
+
+ sj.add("\"" + tags + "\"");
+ sj.add("\"" + notes + "\"");
+
+ return sj.toString();
+ }
+
+ @Override
+ public Path getExportPath() {
+ return userPrefs.getExportDirectoryPath().resolve(exportSubPath);
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/Exporter.java b/src/main/java/bizbook/logic/commands/exporter/Exporter.java
new file mode 100644
index 00000000000..e7aabb007b3
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/Exporter.java
@@ -0,0 +1,24 @@
+package bizbook.logic.commands.exporter;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import bizbook.logic.commands.exporter.exceptions.InvalidAddressBookException;
+import bizbook.model.ReadOnlyAddressBook;
+
+/**
+ * Represents a class that can export an address book to a particular format
+ */
+public interface Exporter {
+ String MESSAGE_EMPTY_ADDRESS_BOOK = "Address book is empty. Consider adding a person first.";
+
+ /**
+ * Exports the address book
+ */
+ void exportAddressBook(ReadOnlyAddressBook addressBook) throws IOException, InvalidAddressBookException;
+
+ /**
+ * Returns the path that the addressbook will be exported to
+ */
+ Path getExportPath();
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/FileType.java b/src/main/java/bizbook/logic/commands/exporter/FileType.java
new file mode 100644
index 00000000000..5418b4936e4
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/FileType.java
@@ -0,0 +1,55 @@
+package bizbook.logic.commands.exporter;
+
+import bizbook.model.ReadOnlyUserPrefs;
+
+/**
+ * Represents a file type that can be exported
+ */
+public enum FileType {
+ CSV,
+ VCF;
+
+ public static final String MESSAGE_CONSTRAINTS = "File type should either be CSV or VCF";
+ public static final String MESSAGE_NOT_SUPPORTED = "File type is not supported.";
+
+ /**
+ * Creates an {@link Exporter} for this file type
+ */
+ public Exporter exporter(ReadOnlyUserPrefs userPrefs) {
+ return switch (this) {
+ case CSV -> new CsvExporter(userPrefs);
+ case VCF -> new VcfExporter(userPrefs);
+ default -> throw new UnsupportedOperationException(MESSAGE_NOT_SUPPORTED);
+ };
+ }
+
+ /**
+ * Returns true if this file type has an {@link Exporter}
+ */
+ public boolean hasExporter() {
+ return switch (this) {
+ case CSV, VCF -> true;
+ default -> false;
+ };
+ }
+
+ /**
+ * Creates an {@link Importer} for this file type
+ */
+ public Importer importer() {
+ return switch (this) {
+ case VCF -> new VcfImporter();
+ default -> throw new UnsupportedOperationException(MESSAGE_NOT_SUPPORTED);
+ };
+ }
+
+ /**
+ * Returns true if this file type has an {@link Importer}
+ */
+ public boolean hasImporter() {
+ return switch (this) {
+ case VCF -> true;
+ default -> false;
+ };
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/Importer.java b/src/main/java/bizbook/logic/commands/exporter/Importer.java
new file mode 100644
index 00000000000..7ef4d847429
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/Importer.java
@@ -0,0 +1,19 @@
+package bizbook.logic.commands.exporter;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import bizbook.logic.commands.exporter.exceptions.InvalidFileException;
+import bizbook.model.AddressBook;
+
+/**
+ * Represents a class that can import an address book from a particular format
+ */
+public interface Importer {
+ String MESSAGE_EMPTY_FILE = "There are no people to import from the file.";
+ String MESSAGE_INVALID_FORMAT = "File is not in the proper format or the file is corrupted.";
+ /**
+ * Imports an address book
+ */
+ AddressBook importAddressBook(Path filePath) throws IOException, InvalidFileException;
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/VcfExporter.java b/src/main/java/bizbook/logic/commands/exporter/VcfExporter.java
new file mode 100644
index 00000000000..41284afaed6
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/VcfExporter.java
@@ -0,0 +1,83 @@
+package bizbook.logic.commands.exporter;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import bizbook.commons.util.FileUtil;
+import bizbook.logic.commands.exporter.exceptions.InvalidAddressBookException;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.person.Person;
+import ezvcard.Ezvcard;
+import ezvcard.VCard;
+import ezvcard.property.Address;
+import ezvcard.property.Categories;
+import ezvcard.property.StructuredName;
+
+/**
+ * Represents a class that can export to VCF
+ */
+public class VcfExporter implements Exporter {
+ private final Path exportSubPath = Paths.get("bizbook.vcf");
+ private final ReadOnlyUserPrefs userPrefs;
+
+ /**
+ * Constructs a {@code VcfExporter} class configured with {@code ReadOnlyUserPrefs}
+ */
+ public VcfExporter(ReadOnlyUserPrefs userPrefs) {
+ this.userPrefs = userPrefs;
+ }
+
+ @Override
+ public void exportAddressBook(ReadOnlyAddressBook addressBook) throws IOException, InvalidAddressBookException {
+ if (addressBook.getPersonList().isEmpty()) {
+ throw new InvalidAddressBookException(MESSAGE_EMPTY_ADDRESS_BOOK);
+ }
+
+ List vCards = addressBook.getPersonList()
+ .parallelStream().map(this::convertToVcf).toList();
+ String fileContent = Ezvcard.write(vCards).go();
+
+ Path exportPath = getExportPath();
+ FileUtil.createIfMissing(exportPath);
+ FileUtil.writeToFile(exportPath, fileContent);
+ }
+
+ private VCard convertToVcf(Person person) {
+ // Convert attributes to vCard representable properties
+ // Since we have no indication of which parts of the name is which, set
+ // the given name as full name
+ StructuredName structuredName = new StructuredName();
+ structuredName.setGiven(person.getName().fullName);
+
+ Address address = new Address();
+ address.setStreetAddress(person.getAddress().value);
+
+ Categories categories = new Categories();
+ person.getTags().forEach(tag -> categories.getValues().add(tag.tagName));
+
+ // Create vCard
+ VCard vCard = new VCard();
+ vCard.setFormattedName(person.getName().fullName);
+ vCard.setStructuredName(structuredName);
+ vCard.addTelephoneNumber(person.getPhone().value);
+ vCard.addEmail(person.getEmail().value);
+ vCard.addAddress(address);
+
+ if (!categories.getValues().isEmpty()) {
+ vCard.setCategories(categories);
+ }
+
+ person.getNotes()
+ .forEach(note -> vCard.addNote(note.getNote()));
+
+ return vCard;
+ }
+
+ @Override
+ public Path getExportPath() {
+ return userPrefs.getExportDirectoryPath().resolve(exportSubPath);
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/VcfImporter.java b/src/main/java/bizbook/logic/commands/exporter/VcfImporter.java
new file mode 100644
index 00000000000..c3d4cdc4a3b
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/VcfImporter.java
@@ -0,0 +1,180 @@
+package bizbook.logic.commands.exporter;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import bizbook.commons.util.FileUtil;
+import bizbook.logic.commands.exporter.exceptions.InvalidFileException;
+import bizbook.model.AddressBook;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
+import ezvcard.Ezvcard;
+import ezvcard.VCard;
+import ezvcard.property.Categories;
+import ezvcard.property.FormattedName;
+import ezvcard.property.Telephone;
+
+/**
+ * Represents a class that can import an address book from a VCF file
+ */
+public class VcfImporter implements Importer {
+ public static final String MESSAGE_MISSING_INFORMATION = "A vCard inside the file is missing information needed to "
+ + "make a person.";
+ public static final String MESSAGE_INVALID_INFORMATION = "A vCard inside the file contains information that "
+ + "cannot be converted to make a person.";
+
+ // ================ Validation methods ==============================
+ private void validateNotEmpty(List vCards) throws InvalidFileException {
+ requireNonNull(vCards);
+
+ if (vCards.isEmpty()) {
+ throw new InvalidFileException(MESSAGE_EMPTY_FILE);
+ }
+ }
+
+ private void validateVCard(VCard vCard) throws InvalidFileException {
+ requireNonNull(vCard);
+
+ if (!vCard.validate(vCard.getVersion()).isEmpty()) {
+ throw new InvalidFileException(MESSAGE_INVALID_FORMAT);
+ }
+ }
+
+ // ================ Import methods ==============================
+ @Override
+ public AddressBook importAddressBook(Path filePath) throws IOException, InvalidFileException {
+ requireNonNull(filePath);
+
+ List vCards = parseVCardFromFile(filePath);
+ return convertToAddressBook(vCards);
+ }
+
+ /**
+ * Loads and parses the vCards from a file path.
+ *
+ * @param filePath path to the VCF file
+ * @return a list of vCards
+ * @throws IOException when the file could not be loaded
+ * @throws InvalidFileException when the file is empty
+ */
+ private List parseVCardFromFile(Path filePath) throws IOException, InvalidFileException {
+ String contents = FileUtil.readFromFile(filePath);
+ List vCards = Ezvcard.parse(contents).all();
+
+ validateNotEmpty(vCards);
+ return vCards;
+ }
+
+ /**
+ * Converts a list of vCards to an AddressBook
+ *
+ * @param vCards list of vCards
+ * @return address book with the vCards
+ * @throws InvalidFileException when any vCard cannot be converted
+ */
+ private AddressBook convertToAddressBook(List vCards) throws InvalidFileException {
+ requireNonNull(vCards);
+
+ AddressBook addressBook = new AddressBook();
+ for (VCard vCard : vCards) {
+ addressBook.addPerson(convertToPerson(vCard));
+ }
+
+ return addressBook;
+ }
+
+ /**
+ * Converts a {@link VCard} to a {@link Person}
+ *
+ * @throws InvalidFileException when the vCard cannot be converted
+ */
+ private Person convertToPerson(VCard vCard) throws InvalidFileException {
+ validateVCard(vCard);
+
+ PersonVCard personVCard = new PersonVCard(vCard);
+
+ try {
+ return new Person(
+ personVCard.getName(),
+ personVCard.getPhone(),
+ personVCard.getEmail(),
+ personVCard.getAddress(),
+ personVCard.getTags(),
+ personVCard.getNotes()
+ );
+ } catch (IllegalArgumentException iae) {
+ throw new InvalidFileException(MESSAGE_INVALID_INFORMATION);
+ }
+ }
+
+ private static class PersonVCard {
+ private final VCard vCard;
+ PersonVCard(VCard vCard) {
+ this.vCard = vCard;
+ }
+
+ private void validateInfoNotNull(Object object) throws InvalidFileException {
+ if (object == null) {
+ throw new InvalidFileException(MESSAGE_MISSING_INFORMATION);
+ }
+ }
+
+ private void validateNotEmpty(List> objects) throws InvalidFileException {
+ if (objects.isEmpty()) {
+ throw new InvalidFileException(MESSAGE_MISSING_INFORMATION);
+ }
+ }
+
+ Name getName() throws InvalidFileException {
+ FormattedName name = vCard.getFormattedName();
+ validateInfoNotNull(name);
+ return new Name(name.getValue());
+ }
+
+ Phone getPhone() throws InvalidFileException {
+ List numbers = vCard.getTelephoneNumbers();
+ validateNotEmpty(numbers);
+ return new Phone(numbers.get(0).getText());
+ }
+
+ Email getEmail() throws InvalidFileException {
+ List emails = vCard.getEmails();
+ validateNotEmpty(emails);
+ return new Email(emails.get(0).getValue());
+ }
+
+ Address getAddress() throws InvalidFileException {
+ List addresses = vCard.getAddresses();
+ validateNotEmpty(addresses);
+ return new Address(addresses.get(0).getStreetAddressFull());
+ }
+
+ Set getTags() {
+ Categories categories = vCard.getCategories();
+ if (categories == null) {
+ return new LinkedHashSet<>();
+ }
+
+ return vCard.getCategories().getValues().parallelStream()
+ .map(Tag::new)
+ .collect(Collectors.toSet());
+ }
+
+ ArrayList getNotes() {
+ return vCard.getNotes().parallelStream()
+ .map(note -> new Note(note.getValue())).collect(Collectors.toCollection(ArrayList::new));
+ }
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/exceptions/InvalidAddressBookException.java b/src/main/java/bizbook/logic/commands/exporter/exceptions/InvalidAddressBookException.java
new file mode 100644
index 00000000000..4047c451bdc
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/exceptions/InvalidAddressBookException.java
@@ -0,0 +1,13 @@
+package bizbook.logic.commands.exporter.exceptions;
+
+/**
+ * Represents an error that is caused because something is wrong with the {@link bizbook.model.AddressBook}.
+ */
+public class InvalidAddressBookException extends Exception {
+ /**
+ * Constructs a new {@code InvalidAddressBookException} with the specified detail {@code message}.
+ */
+ public InvalidAddressBookException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/bizbook/logic/commands/exporter/exceptions/InvalidFileException.java b/src/main/java/bizbook/logic/commands/exporter/exceptions/InvalidFileException.java
new file mode 100644
index 00000000000..1a357a91f35
--- /dev/null
+++ b/src/main/java/bizbook/logic/commands/exporter/exceptions/InvalidFileException.java
@@ -0,0 +1,13 @@
+package bizbook.logic.commands.exporter.exceptions;
+
+/**
+ * Represents an error that is caused because something is wrong with the loaded file.
+ */
+public class InvalidFileException extends Exception {
+ /**
+ * Constructs a new {@code InvalidFileException} with the specified detail {@code message}.
+ */
+ public InvalidFileException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/bizbook/logic/parser/AddCommandParser.java
similarity index 68%
rename from src/main/java/seedu/address/logic/parser/AddCommandParser.java
rename to src/main/java/bizbook/logic/parser/AddCommandParser.java
index 4ff1a97ed77..029bbd4ec9f 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/bizbook/logic/parser/AddCommandParser.java
@@ -1,23 +1,25 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
-import static seedu.address.logic.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 static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import java.util.ArrayList;
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;
+import bizbook.logic.commands.AddCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
/**
* Parses input arguments and creates a new AddCommand object
@@ -27,6 +29,7 @@ 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 {
@@ -44,8 +47,10 @@ public AddCommand parse(String args) throws ParseException {
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));
+ // Set notes to a new empty arrayList first as it is optional
+ ArrayList notes = new ArrayList<>();
- Person person = new Person(name, phone, email, address, tagList);
+ Person person = new Person(name, phone, email, address, tagList, notes);
return new AddCommand(person);
}
diff --git a/src/main/java/bizbook/logic/parser/AddNotesCommandParser.java b/src/main/java/bizbook/logic/parser/AddNotesCommandParser.java
new file mode 100644
index 00000000000..48e262cf13f
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/AddNotesCommandParser.java
@@ -0,0 +1,43 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES;
+import static java.util.Objects.requireNonNull;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.logic.commands.AddNoteCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.Note;
+
+/**
+ * Parses input arguments and creates a new AddNotesCommand object
+ */
+public class AddNotesCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddNotesCommand
+ * and returns a AddNotesCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddNoteCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args,
+ PREFIX_NOTES);
+
+ Index index;
+ Note note;
+ try {
+ String noteName = argMultimap.getValue(PREFIX_NOTES).orElse("");
+ note = ParserUtil.parseNote(noteName);
+
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddNoteCommand.MESSAGE_USAGE), ive);
+ }
+
+ return new AddNoteCommand(index, note);
+ }
+}
diff --git a/src/main/java/bizbook/logic/parser/AddressBookParser.java b/src/main/java/bizbook/logic/parser/AddressBookParser.java
new file mode 100644
index 00000000000..2d4aa1e1ad2
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/AddressBookParser.java
@@ -0,0 +1,134 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import bizbook.commons.core.LogsCenter;
+import bizbook.logic.commands.AddCommand;
+import bizbook.logic.commands.AddNoteCommand;
+import bizbook.logic.commands.ClearCommand;
+import bizbook.logic.commands.Command;
+import bizbook.logic.commands.DeleteCommand;
+import bizbook.logic.commands.DeleteNoteCommand;
+import bizbook.logic.commands.DeleteTagCommand;
+import bizbook.logic.commands.EditCommand;
+import bizbook.logic.commands.EditNoteCommand;
+import bizbook.logic.commands.ExitCommand;
+import bizbook.logic.commands.ExportCommand;
+import bizbook.logic.commands.FindCommand;
+import bizbook.logic.commands.HelpCommand;
+import bizbook.logic.commands.ImportCommand;
+import bizbook.logic.commands.ListCommand;
+import bizbook.logic.commands.PinCommand;
+import bizbook.logic.commands.RedoCommand;
+import bizbook.logic.commands.ToggleCommand;
+import bizbook.logic.commands.UndoCommand;
+import bizbook.logic.commands.UnpinCommand;
+import bizbook.logic.commands.ViewCommand;
+import bizbook.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+)(?.*)");
+ private static final Logger logger = LogsCenter.getLogger(AddressBookParser.class);
+
+ /**
+ * 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").toLowerCase();
+ final String arguments = matcher.group("arguments");
+
+ // Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
+ // log messages such as the one below.
+ // Lower level log messages are used sparingly to minimize noise in the code.
+ logger.fine("Command word: " + commandWord + "; Arguments: " + 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();
+
+ case ViewCommand.COMMAND_WORD:
+ return new ViewCommandParser().parse(arguments);
+
+ case DeleteTagCommand.COMMAND_WORD:
+ return new DeleteTagCommandParser().parse(arguments);
+
+ case AddNoteCommand.COMMAND_WORD:
+ return new AddNotesCommandParser().parse(arguments);
+
+ case EditNoteCommand.COMMAND_WORD:
+ return new EditNotesCommandParser().parse(arguments);
+
+ case DeleteNoteCommand.COMMAND_WORD:
+ return new DeleteNotesCommandParser().parse(arguments);
+
+ case PinCommand.COMMAND_WORD:
+ return new PinCommandParser().parse(arguments);
+
+ case UnpinCommand.COMMAND_WORD:
+ return new UnpinCommandParser().parse(arguments);
+
+
+ case ExportCommand.COMMAND_WORD:
+ return new ExportCommandParser().parse(arguments);
+
+ case ImportCommand.COMMAND_WORD:
+ return new ImportCommandParser().parse(arguments);
+
+ case UndoCommand.COMMAND_WORD:
+ return new UndoCommand();
+
+ case RedoCommand.COMMAND_WORD:
+ return new RedoCommand();
+
+ case ToggleCommand.COMMAND_WORD:
+ return new ToggleCommand();
+
+ default:
+ logger.finer("This user input caused a ParseException: " + userInput);
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/bizbook/logic/parser/ArgumentMultimap.java
similarity index 95%
rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
rename to src/main/java/bizbook/logic/parser/ArgumentMultimap.java
index 21e26887a83..de4e3fa01ab 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/bizbook/logic/parser/ArgumentMultimap.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
import java.util.ArrayList;
import java.util.HashMap;
@@ -7,8 +7,8 @@
import java.util.Optional;
import java.util.stream.Stream;
-import seedu.address.logic.Messages;
-import seedu.address.logic.parser.exceptions.ParseException;
+import bizbook.logic.Messages;
+import bizbook.logic.parser.exceptions.ParseException;
/**
* Stores mapping of prefixes to their respective arguments.
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/bizbook/logic/parser/ArgumentTokenizer.java
similarity index 99%
rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
rename to src/main/java/bizbook/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..fa9238663d3 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/bizbook/logic/parser/ArgumentTokenizer.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/bizbook/logic/parser/CliSyntax.java
similarity index 58%
rename from src/main/java/seedu/address/logic/parser/CliSyntax.java
rename to src/main/java/bizbook/logic/parser/CliSyntax.java
index 75b1a9bf119..0b7fff66636 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/bizbook/logic/parser/CliSyntax.java
@@ -1,7 +1,8 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
/**
- * Contains Command Line Interface (CLI) syntax definitions common to multiple commands
+ * Contains Command Line Interface (CLI) syntax definitions common to multiple
+ * commands
*/
public class CliSyntax {
@@ -11,5 +12,8 @@ public class CliSyntax {
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/");
-
+ public static final Prefix PREFIX_NOTES = new Prefix("n/");
+ public static final Prefix PREFIX_NOTES_INDEX = new Prefix("i/");
+ public static final Prefix PREFIX_FILE = new Prefix("f/");
+ public static final Prefix PREFIX_PATH = new Prefix("p/");
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/bizbook/logic/parser/DeleteCommandParser.java
similarity index 74%
rename from src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
rename to src/main/java/bizbook/logic/parser/DeleteCommandParser.java
index 3527fe76a3e..6cc092b4e00 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/bizbook/logic/parser/DeleteCommandParser.java
@@ -1,10 +1,10 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.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;
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.DeleteCommand;
+import bizbook.logic.parser.exceptions.ParseException;
/**
* Parses input arguments and creates a new DeleteCommand object
@@ -14,6 +14,7 @@ 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 {
diff --git a/src/main/java/bizbook/logic/parser/DeleteNotesCommandParser.java b/src/main/java/bizbook/logic/parser/DeleteNotesCommandParser.java
new file mode 100644
index 00000000000..3e2343d02e6
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/DeleteNotesCommandParser.java
@@ -0,0 +1,43 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES_INDEX;
+import static java.util.Objects.requireNonNull;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.logic.commands.DeleteNoteCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteNotesCommand object
+ */
+public class DeleteNotesCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteNotesCommand
+ * and returns a DeleteNotesCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteNoteCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args,
+ PREFIX_NOTES_INDEX);
+
+ Index index;
+ Index noteIndex;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+
+ String noteIndexName = argMultimap.getValue(PREFIX_NOTES_INDEX).orElse("");
+ noteIndex = ParserUtil.parseIndex(noteIndexName);
+
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteNoteCommand.MESSAGE_USAGE), ive);
+ }
+
+ return new DeleteNoteCommand(index, noteIndex);
+ }
+}
diff --git a/src/main/java/bizbook/logic/parser/DeleteTagCommandParser.java b/src/main/java/bizbook/logic/parser/DeleteTagCommandParser.java
new file mode 100644
index 00000000000..3696a12b92d
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/DeleteTagCommandParser.java
@@ -0,0 +1,45 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static java.util.Objects.requireNonNull;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.logic.commands.DeleteTagCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.tag.Tag;
+
+/**
+ * Parses input arguments and returns a new DeleteTagCommand object
+ */
+public class DeleteTagCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code userInput} of arguments in the context of the DeleteTagCommand
+ * and returns a DeleteTagCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteTagCommand parse(String userInput) throws ParseException {
+
+ requireNonNull(userInput);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_TAG);
+
+ Index personIndex;
+ Tag tagToDelete;
+
+ try {
+ personIndex = ParserUtil.parseIndex(argMultimap.getPreamble());
+ String tagName = argMultimap.getValue(PREFIX_TAG).orElse("");
+ tagToDelete = ParserUtil.parseTag(tagName);
+
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTagCommand.MESSAGE_USAGE), ive);
+ }
+
+ return new DeleteTagCommand(personIndex, tagToDelete);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/bizbook/logic/parser/EditCommandParser.java
similarity index 80%
rename from src/main/java/seedu/address/logic/parser/EditCommandParser.java
rename to src/main/java/bizbook/logic/parser/EditCommandParser.java
index 46b3309a78b..8f8f7f7e6c2 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/bizbook/logic/parser/EditCommandParser.java
@@ -1,23 +1,23 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.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;
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.EditCommand;
+import bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.tag.Tag;
/**
* Parses input arguments and creates a new EditCommand object
@@ -27,6 +27,7 @@ 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 {
diff --git a/src/main/java/bizbook/logic/parser/EditNotesCommandParser.java b/src/main/java/bizbook/logic/parser/EditNotesCommandParser.java
new file mode 100644
index 00000000000..ef4dac07818
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/EditNotesCommandParser.java
@@ -0,0 +1,48 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES_INDEX;
+import static java.util.Objects.requireNonNull;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.logic.commands.EditNoteCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.Note;
+
+/**
+ * Parses input arguments and returns a new EditNotesCommand object
+ */
+public class EditNotesCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditNotesCommand
+ * and returns a EditNotesCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditNoteCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args,
+ PREFIX_NOTES_INDEX, PREFIX_NOTES);
+
+ Index personIndex;
+ Index noteIndex;
+ Note note;
+ try {
+ personIndex = ParserUtil.parseIndex(argMultimap.getPreamble());
+
+ String noteIndexName = argMultimap.getValue(PREFIX_NOTES_INDEX).orElse("");
+ noteIndex = ParserUtil.parseIndex(noteIndexName);
+ String noteName = argMultimap.getValue(PREFIX_NOTES).orElse("");
+ note = ParserUtil.parseNote(noteName);
+
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditNoteCommand.MESSAGE_USAGE), ive);
+ }
+
+ return new EditNoteCommand(personIndex, noteIndex, note);
+ }
+}
diff --git a/src/main/java/bizbook/logic/parser/ExportCommandParser.java b/src/main/java/bizbook/logic/parser/ExportCommandParser.java
new file mode 100644
index 00000000000..2033c80b826
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/ExportCommandParser.java
@@ -0,0 +1,41 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.Messages.MESSAGE_UNSUPPORTED_FILE_TYPE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_FILE;
+import static java.util.Objects.requireNonNull;
+
+import bizbook.logic.commands.ExportCommand;
+import bizbook.logic.commands.exporter.FileType;
+import bizbook.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and create a new ExportCsvCommand object
+ */
+public class ExportCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ExportCsvCommand
+ * and returns a ExportCsvCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ExportCommand parse(String args) throws ParseException {
+
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_FILE);
+
+ if (argMultimap.getValue(PREFIX_FILE).isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ExportCommand.MESSAGE_USAGE));
+ }
+
+ FileType fileType = ParserUtil.parseFileType(argMultimap.getValue(PREFIX_FILE).get());
+
+ if (!fileType.hasExporter()) {
+ throw new ParseException(
+ String.format(MESSAGE_UNSUPPORTED_FILE_TYPE, ExportCommand.MESSAGE_USAGE));
+ }
+
+ return new ExportCommand(fileType);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/bizbook/logic/parser/FindCommandParser.java
similarity index 75%
rename from src/main/java/seedu/address/logic/parser/FindCommandParser.java
rename to src/main/java/bizbook/logic/parser/FindCommandParser.java
index 2867bde857b..ea8ae2430e6 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/bizbook/logic/parser/FindCommandParser.java
@@ -1,12 +1,12 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.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;
+import bizbook.logic.commands.FindCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.NameContainsKeywordsPredicate;
/**
* Parses input arguments and creates a new FindCommand object
@@ -16,6 +16,7 @@ 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 {
diff --git a/src/main/java/bizbook/logic/parser/ImportCommandParser.java b/src/main/java/bizbook/logic/parser/ImportCommandParser.java
new file mode 100644
index 00000000000..36845215d70
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/ImportCommandParser.java
@@ -0,0 +1,53 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.Messages.MESSAGE_INVALID_FILE_PATH;
+import static bizbook.logic.Messages.MESSAGE_UNSUPPORTED_FILE_TYPE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_FILE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PATH;
+import static java.util.Objects.requireNonNull;
+
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+
+import bizbook.logic.commands.ImportCommand;
+import bizbook.logic.commands.exporter.FileType;
+import bizbook.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and create a new ImportCommand object
+ */
+public class ImportCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ImportCommand
+ * and returns a ImportCsvCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ImportCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_FILE, PREFIX_PATH);
+
+ if (argMultimap.getValue(PREFIX_FILE).isEmpty()
+ || argMultimap.getValue(PREFIX_PATH).isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE));
+ }
+
+ FileType fileType = ParserUtil.parseFileType(argMultimap.getValue(PREFIX_FILE).get());
+ String rawPath = argMultimap.getValue(PREFIX_PATH).get();
+ Path path;
+ try {
+ path = Path.of(rawPath);
+ } catch (InvalidPathException ipe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_FILE_PATH, rawPath));
+ }
+
+ if (!fileType.hasImporter()) {
+ throw new ParseException(
+ String.format(MESSAGE_UNSUPPORTED_FILE_TYPE, ImportCommand.MESSAGE_USAGE));
+ }
+
+ return new ImportCommand(fileType, path);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/bizbook/logic/parser/Parser.java
similarity index 72%
rename from src/main/java/seedu/address/logic/parser/Parser.java
rename to src/main/java/bizbook/logic/parser/Parser.java
index d6551ad8e3f..921520db709 100644
--- a/src/main/java/seedu/address/logic/parser/Parser.java
+++ b/src/main/java/bizbook/logic/parser/Parser.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.parser.exceptions.ParseException;
+import bizbook.logic.commands.Command;
+import bizbook.logic.parser.exceptions.ParseException;
/**
* Represents a Parser that is able to parse user input into a {@code Command} of type {@code T}.
@@ -10,6 +10,7 @@ public interface Parser {
/**
* Parses {@code userInput} into a command and returns it.
+ *
* @throws ParseException if {@code userInput} does not conform the expected format
*/
T parse(String userInput) throws ParseException;
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/bizbook/logic/parser/ParserUtil.java
similarity index 70%
rename from src/main/java/seedu/address/logic/parser/ParserUtil.java
rename to src/main/java/bizbook/logic/parser/ParserUtil.java
index b117acb9c55..cc1ec121a1e 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/bizbook/logic/parser/ParserUtil.java
@@ -1,19 +1,21 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
import static java.util.Objects.requireNonNull;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
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 bizbook.commons.core.index.Index;
+import bizbook.commons.util.StringUtil;
+import bizbook.logic.commands.exporter.FileType;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -25,6 +27,7 @@ public class ParserUtil {
/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
+ *
* @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
*/
public static Index parseIndex(String oneBasedIndex) throws ParseException {
@@ -115,10 +118,42 @@ public static Tag parseTag(String tag) throws ParseException {
*/
public static Set parseTags(Collection tags) throws ParseException {
requireNonNull(tags);
- final Set tagSet = new HashSet<>();
+ final Set tagSet = new LinkedHashSet<>();
for (String tagName : tags) {
tagSet.add(parseTag(tagName));
}
return tagSet;
}
+
+ /**
+ * Parses a {@code String note} into a {@code Note}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code note} is invalid.
+ */
+ public static Note parseNote(String note) throws ParseException {
+ requireNonNull(note);
+ String trimmedNote = note.trim();
+ if (!Note.isValidNoteName(trimmedNote)) {
+ throw new ParseException(Note.MESSAGE_CONSTRAINTS);
+ }
+ return new Note(trimmedNote);
+ }
+
+ /**
+ * Parses a {@code String fileType} into a valid {@code fileType}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code fileType} is invalid.
+ */
+ public static FileType parseFileType(String fileType) throws ParseException {
+ requireNonNull(fileType);
+ String trimmedFileType = fileType.trim().toUpperCase();
+
+ try {
+ return FileType.valueOf(trimmedFileType);
+ } catch (IllegalArgumentException argex) {
+ throw new ParseException(FileType.MESSAGE_CONSTRAINTS);
+ }
+ }
}
diff --git a/src/main/java/bizbook/logic/parser/PinCommandParser.java b/src/main/java/bizbook/logic/parser/PinCommandParser.java
new file mode 100644
index 00000000000..010dc97b316
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/PinCommandParser.java
@@ -0,0 +1,29 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.PinCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new PinCommand object
+ */
+public class PinCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the PinCommand
+ * and return a PinCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public PinCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new PinCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, PinCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/bizbook/logic/parser/Prefix.java
similarity index 95%
rename from src/main/java/seedu/address/logic/parser/Prefix.java
rename to src/main/java/bizbook/logic/parser/Prefix.java
index 348b7686c8a..f2be0a0495c 100644
--- a/src/main/java/seedu/address/logic/parser/Prefix.java
+++ b/src/main/java/bizbook/logic/parser/Prefix.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
/**
* A prefix that marks the beginning of an argument in an arguments string.
diff --git a/src/main/java/bizbook/logic/parser/UnpinCommandParser.java b/src/main/java/bizbook/logic/parser/UnpinCommandParser.java
new file mode 100644
index 00000000000..feb3096503a
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/UnpinCommandParser.java
@@ -0,0 +1,29 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.UnpinCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new UnpinCommand object
+ */
+public class UnpinCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the UnpinCommand
+ * and return a UnpinCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public UnpinCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new UnpinCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnpinCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/bizbook/logic/parser/ViewCommandParser.java b/src/main/java/bizbook/logic/parser/ViewCommandParser.java
new file mode 100644
index 00000000000..0a418dfd230
--- /dev/null
+++ b/src/main/java/bizbook/logic/parser/ViewCommandParser.java
@@ -0,0 +1,29 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.ViewCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new ViewCommand object
+ */
+public class ViewCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ViewCommand
+ * and returns a ViewCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ViewCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new ViewCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/bizbook/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/bizbook/logic/parser/exceptions/ParseException.java
index 158a1a54c1c..cfaeb79a415 100644
--- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
+++ b/src/main/java/bizbook/logic/parser/exceptions/ParseException.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.parser.exceptions;
+package bizbook.logic.parser.exceptions;
-import seedu.address.commons.exceptions.IllegalValueException;
+import bizbook.commons.exceptions.IllegalValueException;
/**
* Represents a parse error encountered by a parser.
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/bizbook/model/AddressBook.java
similarity index 62%
rename from src/main/java/seedu/address/model/AddressBook.java
rename to src/main/java/bizbook/model/AddressBook.java
index 73397161e84..6b6a3558b2d 100644
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ b/src/main/java/bizbook/model/AddressBook.java
@@ -1,13 +1,13 @@
-package seedu.address.model;
+package bizbook.model;
import static java.util.Objects.requireNonNull;
import java.util.List;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.model.person.Person;
+import bizbook.model.person.UniquePersonList;
import javafx.collections.ObservableList;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
/**
* Wraps all data at the address-book level
@@ -16,6 +16,7 @@
public class AddressBook implements ReadOnlyAddressBook {
private final UniquePersonList persons;
+ private final UniquePersonList pinnedPersons;
/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
@@ -26,6 +27,7 @@ public class AddressBook implements ReadOnlyAddressBook {
*/
{
persons = new UniquePersonList();
+ pinnedPersons = new UniquePersonList();
}
public AddressBook() {}
@@ -54,6 +56,8 @@ public void setPersons(List persons) {
public void resetData(ReadOnlyAddressBook newData) {
requireNonNull(newData);
+ // Empty the pinned person list since we are reseting the addressbook
+ setPinnedPersons(newData.getPinnedPersonList());
setPersons(newData.getPersonList());
}
@@ -84,6 +88,9 @@ public void setPerson(Person target, Person editedPerson) {
requireNonNull(editedPerson);
persons.setPerson(target, editedPerson);
+ if (isPinned(target)) {
+ pinnedPersons.setPerson(target, editedPerson);
+ }
}
/**
@@ -92,6 +99,52 @@ public void setPerson(Person target, Person editedPerson) {
*/
public void removePerson(Person key) {
persons.remove(key);
+ if (isPinned(key)) {
+ removePinnedPerson(key);
+ }
+ }
+
+ //=========== Pinned Person List Accessors ===============================================================
+
+ /**
+ * Returns true if a person with the same identity as {@code person} exists in the pinned list.
+ */
+ public boolean isPinned(Person person) {
+ requireNonNull(person);
+ return pinnedPersons.contains(person);
+ }
+
+ /**
+ * Returns an unmodifiable view of the pinned person list.
+ */
+ public ObservableList getPinnedPersonList() {
+ return pinnedPersons.asUnmodifiableObservableList();
+ }
+
+ /**
+ * Replaces the contents of the pinned list with {@code persons}.
+ * {@code persons} must not contain duplicate persons.
+ */
+ public void setPinnedPersons(List persons) {
+ this.pinnedPersons.setPersons(persons);
+ }
+
+ /**
+ * Adds the {@code person} in the pinned contact list.
+ *
+ * @param person The {@code person} in the contact list to be pinned.
+ */
+ public void addPinnedPerson(Person person) {
+ this.pinnedPersons.add(person);
+ }
+
+ /**
+ * Remove the {@code person} in the pinned contact list.
+ *
+ * @param person The {@code person} in the contact list to be unpinned.
+ */
+ public void removePinnedPerson(Person person) {
+ this.pinnedPersons.remove(person);
}
//// util methods
@@ -120,7 +173,8 @@ public boolean equals(Object other) {
}
AddressBook otherAddressBook = (AddressBook) other;
- return persons.equals(otherAddressBook.persons);
+ return persons.equals(otherAddressBook.persons)
+ && pinnedPersons.equals(otherAddressBook.pinnedPersons);
}
@Override
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/bizbook/model/Model.java
similarity index 55%
rename from src/main/java/seedu/address/model/Model.java
rename to src/main/java/bizbook/model/Model.java
index d54df471c1f..3defcb29501 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/bizbook/model/Model.java
@@ -1,11 +1,12 @@
-package seedu.address.model;
+package bizbook.model;
import java.nio.file.Path;
import java.util.function.Predicate;
+import bizbook.commons.core.GuiSettings;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
/**
* The API of the Model component.
@@ -39,6 +40,11 @@ public interface Model {
*/
Path getAddressBookFilePath();
+ /**
+ * Returns the person who will be focused on.
+ */
+ ObjectProperty getFocusedPerson();
+
/**
* Sets the user prefs' address book file path.
*/
@@ -81,7 +87,67 @@ public interface Model {
/**
* 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);
+
+ /** Returns an unmodifiable view of the pinned person list */
+ ObservableList getPinnedPersonList();
+
+ /**
+ * Returns true if a person with the same identity as {@code person} exists in the pinned list.
+ */
+ boolean isPinned(Person person);
+
+ /**
+ * Adds the {@code person} in the pinned contact list.
+ *
+ * @param person The {@code person} in the contact list to be pinned.
+ */
+ void pinPerson(Person person);
+
+ /**
+ * Remove the {@code person} in the pinned contact list.
+ *
+ * @param person The {@code person} in the contact list to be unpinned.
+ */
+ void unpinPerson(Person person);
+
+ /**
+ * Checks if there is a newer version that can be reverted to or not.
+ */
+ boolean canRedo();
+
+ /**
+ * Checks if there is a version that can be reverted to or not.
+ */
+ boolean canUndo();
+
+ /**
+ * Saves the current state of the {@code AddressBook} into a version history list.
+ */
+ void saveAddressBookVersion();
+
+ /**
+ * Reverts the {@code AddressBook} to the most recent saved version.
+ */
+ void revertAddressBookVersion();
+
+ /**
+ * Reverts the {@code AddressBook} to the most recent saved version.
+ */
+ void redoAddressBookVersion();
+
+ /**
+ * Sets the focus person to {@code person}.
+ */
+ void setFocusPerson(Person person);
+
+ /**
+ * Cheks if the focus person needs to be updated.
+ * If {@code previousPerson} is the focused person then update it with {@code currentPerson}.
+ */
+ void updateFocusPerson(Person previousPerson, Person currentPerson);
+
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/bizbook/model/ModelManager.java
similarity index 66%
rename from src/main/java/seedu/address/model/ModelManager.java
rename to src/main/java/bizbook/model/ModelManager.java
index 57bc563fde6..f653c1afbc8 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/bizbook/model/ModelManager.java
@@ -1,17 +1,19 @@
-package seedu.address.model;
+package bizbook.model;
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.nio.file.Path;
+import java.util.Objects;
import java.util.function.Predicate;
import java.util.logging.Logger;
+import bizbook.commons.core.GuiSettings;
+import bizbook.commons.core.LogsCenter;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
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.
@@ -19,9 +21,10 @@
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
- private final AddressBook addressBook;
+ private final VersionedAddressBook addressBook;
private final UserPrefs userPrefs;
private final FilteredList filteredPersons;
+ private final ObjectProperty focusedPerson;
/**
* Initializes a ModelManager with the given addressBook and userPrefs.
@@ -31,9 +34,10 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs
logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
- this.addressBook = new AddressBook(addressBook);
+ this.addressBook = new VersionedAddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ this.focusedPerson = Person.personProperty(null);
}
public ModelManager() {
@@ -87,6 +91,11 @@ public ReadOnlyAddressBook getAddressBook() {
return addressBook;
}
+ @Override
+ public ObjectProperty getFocusedPerson() {
+ return this.focusedPerson;
+ }
+
@Override
public boolean hasPerson(Person person) {
requireNonNull(person);
@@ -107,10 +116,69 @@ public void addPerson(Person person) {
@Override
public void setPerson(Person target, Person editedPerson) {
requireAllNonNull(target, editedPerson);
-
addressBook.setPerson(target, editedPerson);
}
+ @Override
+ public ObservableList getPinnedPersonList() {
+ return addressBook.getPinnedPersonList();
+ }
+
+ @Override
+ public boolean isPinned(Person person) {
+ requireNonNull(person);
+ return addressBook.isPinned(person);
+ }
+
+ @Override
+ public void pinPerson(Person person) {
+ requireNonNull(person);
+ this.addressBook.addPinnedPerson(person);
+ }
+
+ @Override
+ public void unpinPerson(Person person) {
+ requireNonNull(person);
+ this.addressBook.removePinnedPerson(person);
+ }
+
+ @Override
+ public boolean canRedo() {
+ return addressBook.canRedo();
+ }
+
+ @Override
+ public boolean canUndo() {
+ return addressBook.canUndo();
+ }
+
+ @Override
+ public void saveAddressBookVersion() {
+ addressBook.commit();
+ }
+
+ @Override
+ public void revertAddressBookVersion() {
+ addressBook.undo();
+ }
+
+ @Override
+ public void redoAddressBookVersion() {
+ addressBook.redo();
+ }
+
+ @Override
+ public void setFocusPerson(Person person) {
+ focusedPerson.set(person);
+ }
+
+ @Override
+ public void updateFocusPerson(Person previousPerson, Person currentPerson) {
+ if (previousPerson.equals(focusedPerson.get())) {
+ setFocusPerson(currentPerson);
+ }
+ }
+
//=========== Filtered Person List Accessors =============================================================
/**
@@ -142,7 +210,8 @@ public boolean equals(Object other) {
ModelManager otherModelManager = (ModelManager) other;
return addressBook.equals(otherModelManager.addressBook)
&& userPrefs.equals(otherModelManager.userPrefs)
- && filteredPersons.equals(otherModelManager.filteredPersons);
+ && filteredPersons.equals(otherModelManager.filteredPersons)
+ && Objects.equals(focusedPerson.get(), otherModelManager.focusedPerson.get());
}
}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/bizbook/model/ReadOnlyAddressBook.java
similarity index 55%
rename from src/main/java/seedu/address/model/ReadOnlyAddressBook.java
rename to src/main/java/bizbook/model/ReadOnlyAddressBook.java
index 6ddc2cd9a29..a4ecc8f412c 100644
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ b/src/main/java/bizbook/model/ReadOnlyAddressBook.java
@@ -1,7 +1,7 @@
-package seedu.address.model;
+package bizbook.model;
+import bizbook.model.person.Person;
import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
/**
* Unmodifiable view of an address book
@@ -14,4 +14,10 @@ public interface ReadOnlyAddressBook {
*/
ObservableList getPersonList();
+ /**
+ * Returns an unmodifiable view of the pinned person list.
+ * This list will not contain any duplicate persons.
+ */
+ ObservableList getPinnedPersonList();
+
}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/bizbook/model/ReadOnlyUserPrefs.java
similarity index 65%
rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
rename to src/main/java/bizbook/model/ReadOnlyUserPrefs.java
index befd58a4c73..fb5083cc3fb 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/bizbook/model/ReadOnlyUserPrefs.java
@@ -1,8 +1,8 @@
-package seedu.address.model;
+package bizbook.model;
import java.nio.file.Path;
-import seedu.address.commons.core.GuiSettings;
+import bizbook.commons.core.GuiSettings;
/**
* Unmodifiable view of user prefs.
@@ -13,4 +13,5 @@ public interface ReadOnlyUserPrefs {
Path getAddressBookFilePath();
+ Path getExportDirectoryPath();
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/bizbook/model/UserPrefs.java
similarity index 71%
rename from src/main/java/seedu/address/model/UserPrefs.java
rename to src/main/java/bizbook/model/UserPrefs.java
index 6be655fb4c7..6a3865daf9d 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/bizbook/model/UserPrefs.java
@@ -1,4 +1,4 @@
-package seedu.address.model;
+package bizbook.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 bizbook.commons.core.GuiSettings;
/**
* Represents User's preferences.
@@ -14,7 +14,8 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path addressBookFilePath = Paths.get("data" , "bizbook.json");
+ private Path exportDirectoryPath = Paths.get("exports");
/**
* Creates a {@code UserPrefs} with default values.
@@ -36,8 +37,10 @@ public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setExportDirectoryPath(newUserPrefs.getExportDirectoryPath());
}
+ @Override
public GuiSettings getGuiSettings() {
return guiSettings;
}
@@ -47,6 +50,7 @@ public void setGuiSettings(GuiSettings guiSettings) {
this.guiSettings = guiSettings;
}
+ @Override
public Path getAddressBookFilePath() {
return addressBookFilePath;
}
@@ -56,6 +60,16 @@ public void setAddressBookFilePath(Path addressBookFilePath) {
this.addressBookFilePath = addressBookFilePath;
}
+ @Override
+ public Path getExportDirectoryPath() {
+ return exportDirectoryPath;
+ }
+
+ public void setExportDirectoryPath(Path exportDirectoryPath) {
+ requireNonNull(exportDirectoryPath);
+ this.exportDirectoryPath = exportDirectoryPath;
+ }
+
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -69,12 +83,13 @@ public boolean equals(Object other) {
UserPrefs otherUserPrefs = (UserPrefs) other;
return guiSettings.equals(otherUserPrefs.guiSettings)
- && addressBookFilePath.equals(otherUserPrefs.addressBookFilePath);
+ && addressBookFilePath.equals(otherUserPrefs.addressBookFilePath)
+ && exportDirectoryPath.equals(otherUserPrefs.exportDirectoryPath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, addressBookFilePath, exportDirectoryPath);
}
@Override
@@ -82,6 +97,7 @@ public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Gui Settings : " + guiSettings);
sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("\nExport data directory location : " + exportDirectoryPath);
return sb.toString();
}
diff --git a/src/main/java/bizbook/model/VersionedAddressBook.java b/src/main/java/bizbook/model/VersionedAddressBook.java
new file mode 100644
index 00000000000..e82062f44e3
--- /dev/null
+++ b/src/main/java/bizbook/model/VersionedAddressBook.java
@@ -0,0 +1,92 @@
+package bizbook.model;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * This class represents the address book with versioning.
+ */
+public class VersionedAddressBook extends AddressBook {
+
+ /* Stores the copy of the previous list of contacts */
+ public final Deque addressBookOlderVersionList = new ArrayDeque<>();
+ /* Stores the copy of the newer versions of the address book */
+ public final Deque addressBookNewerVersionList = new ArrayDeque<>();
+
+ /**
+ * Creates an AddressBook using the Persons in the {@code toBeCopied}
+ */
+ public VersionedAddressBook(ReadOnlyAddressBook toBeCopied) {
+ super(toBeCopied);
+ this.commit();
+ }
+
+ /**
+ * Retrieves the list of the old address book versions.
+ */
+ public Deque getAddressBookHistoryList() {
+ return addressBookOlderVersionList;
+ }
+
+ /**
+ * Checks if there is a newer version that can be reverted to or not.
+ */
+ public boolean canRedo() {
+ return addressBookNewerVersionList.size() > 0;
+ }
+
+ /**
+ * Checks if there is a version that can be reverted to or not.
+ */
+ public boolean canUndo() {
+ return addressBookOlderVersionList.size() > 1;
+ }
+
+ /**
+ * Adds the current version of the {@code AddressBook} into the list.
+ */
+ public void commit() {
+ AddressBook addressBookCopy = new AddressBook();
+ addressBookCopy.setPersons(getPersonList());
+ addressBookCopy.setPinnedPersons(getPinnedPersonList());
+ // If equal to the previous version in the list then do not save
+ if (!addressBookOlderVersionList.isEmpty() && addressBookCopy.equals(addressBookOlderVersionList.getLast())) {
+ return;
+ }
+ // Limit the versions saved to be 5 but 1 slot will be for the base version
+ if (addressBookOlderVersionList.size() == 6) {
+ addressBookOlderVersionList.removeFirst();
+ }
+ addressBookOlderVersionList.addLast(addressBookCopy);
+
+ addressBookNewerVersionList.clear();
+ }
+
+ /**
+ * Reverts to the latest version of the {@code AddressBook} and removed it from the list.
+ */
+ public void undo() {
+ AddressBook currentVersion = addressBookOlderVersionList.removeLast();
+ AddressBook previousVersion = addressBookOlderVersionList.getLast();
+
+ // Limit the versions saved to be 5
+ if (addressBookNewerVersionList.size() == 5) {
+ addressBookNewerVersionList.removeFirst();
+ }
+
+ addressBookNewerVersionList.addLast(currentVersion);
+
+ setPersons(previousVersion.getPersonList());
+ setPinnedPersons(previousVersion.getPinnedPersonList());
+ }
+
+ /**
+ * Reverts to a newer version of the {@code AddressBook} and removed it from the list.
+ */
+ public void redo() {
+ AddressBook newerVersion = addressBookNewerVersionList.removeLast();
+ addressBookOlderVersionList.addLast(newerVersion);
+ setPersons(newerVersion.getPersonList());
+ setPinnedPersons(newerVersion.getPinnedPersonList());
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/bizbook/model/person/Address.java
similarity index 93%
rename from src/main/java/seedu/address/model/person/Address.java
rename to src/main/java/bizbook/model/person/Address.java
index 469a2cc9a1e..3360a3be63f 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/bizbook/model/person/Address.java
@@ -1,7 +1,7 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.commons.util.AppUtil.checkArgument;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
/**
* Represents a Person's address in the address book.
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/bizbook/model/person/Email.java
similarity index 96%
rename from src/main/java/seedu/address/model/person/Email.java
rename to src/main/java/bizbook/model/person/Email.java
index c62e512bc29..1574b79bbda 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/bizbook/model/person/Email.java
@@ -1,7 +1,7 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.commons.util.AppUtil.checkArgument;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
/**
* Represents a Person's email in the address book.
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/bizbook/model/person/Name.java
similarity index 93%
rename from src/main/java/seedu/address/model/person/Name.java
rename to src/main/java/bizbook/model/person/Name.java
index 173f15b9b00..bb7190c6331 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/bizbook/model/person/Name.java
@@ -1,7 +1,7 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.commons.util.AppUtil.checkArgument;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
/**
* Represents a Person's name in the address book.
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/bizbook/model/person/NameContainsKeywordsPredicate.java
similarity index 81%
rename from src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
rename to src/main/java/bizbook/model/person/NameContainsKeywordsPredicate.java
index 62d19be2977..fb0bbe76ff3 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/bizbook/model/person/NameContainsKeywordsPredicate.java
@@ -1,10 +1,9 @@
-package seedu.address.model.person;
+package bizbook.model.person;
import java.util.List;
import java.util.function.Predicate;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.commons.util.ToStringBuilder;
+import bizbook.commons.util.ToStringBuilder;
/**
* Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
@@ -19,7 +18,8 @@ public NameContainsKeywordsPredicate(List keywords) {
@Override
public boolean test(Person person) {
return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ .anyMatch(keyword -> person.getName().fullName.toLowerCase()
+ .contains(keyword.toLowerCase()));
}
@Override
diff --git a/src/main/java/bizbook/model/person/Note.java b/src/main/java/bizbook/model/person/Note.java
new file mode 100644
index 00000000000..913e07613b2
--- /dev/null
+++ b/src/main/java/bizbook/model/person/Note.java
@@ -0,0 +1,79 @@
+package bizbook.model.person;
+
+import static bizbook.commons.util.AppUtil.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import java.util.Objects;
+
+/**
+ * Represents a Person's notes in BizBook.
+ */
+public class Note {
+
+ public static final String MESSAGE_CONSTRAINTS = "Notes should be alphanumeric.";
+ public static final String VALIDATION_REGEX = "(?!^ +$)[\\p{Alnum} ]+";
+
+ private String note;
+
+ /**
+ * Constructs {@code Notes}.
+ *
+ * @param note A valid note.
+ */
+ public Note(String note) {
+ requireNonNull(note);
+ checkArgument(isValidNoteName(note), MESSAGE_CONSTRAINTS);
+ this.note = note;
+ }
+
+ public String getNote() {
+ return this.note;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Note)) {
+ return false;
+ }
+
+ Note otherNotes = (Note) other;
+
+ return note.equalsIgnoreCase(otherNotes.note);
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(note.toLowerCase());
+ }
+
+ /**
+ * Returns true if a given string is a valid note name.
+ */
+ public static boolean isValidNoteName(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns all stored notes as a String.
+ *
+ * @return Notes string to be displayed in details pane
+ */
+ @Override
+ public String toString() {
+ return '[' + note + ']';
+ }
+
+ /**
+ * Returns true if a note is empty and false if not.
+ */
+ public boolean isEmpty() {
+ return note.isEmpty();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/bizbook/model/person/Person.java
similarity index 66%
rename from src/main/java/seedu/address/model/person/Person.java
rename to src/main/java/bizbook/model/person/Person.java
index abe8c46b535..9e5fe8e8fb2 100644
--- a/src/main/java/seedu/address/model/person/Person.java
+++ b/src/main/java/bizbook/model/person/Person.java
@@ -1,14 +1,17 @@
-package seedu.address.model.person;
+package bizbook.model.person;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
+import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.tag.Tag;
+import bizbook.commons.util.ToStringBuilder;
+import bizbook.model.tag.Tag;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ObjectPropertyBase;
/**
* Represents a Person in the address book.
@@ -23,18 +26,21 @@ public class Person {
// Data fields
private final Address address;
- private final Set tags = new HashSet<>();
+ private final Set tags = new LinkedHashSet<>();
+ private final ArrayList notes = new ArrayList<>();
/**
* Every field must be present and not null.
*/
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
+ public Person(Name name, Phone phone, Email email, Address address, Set tags, ArrayList notes) {
requireAllNonNull(name, phone, email, address, tags);
this.name = name;
this.phone = phone;
this.email = email;
this.address = address;
this.tags.addAll(tags);
+ this.notes.addAll(notes);
+
}
public Name getName() {
@@ -61,6 +67,10 @@ public Set getTags() {
return Collections.unmodifiableSet(tags);
}
+ public ArrayList getNotes() {
+ return notes;
+ }
+
/**
* Returns true if both persons have the same name.
* This defines a weaker notion of equality between two persons.
@@ -74,6 +84,29 @@ public boolean isSamePerson(Person otherPerson) {
&& otherPerson.getName().equals(getName());
}
+ /**
+ * Wraps the Person so that it becomes an ObjectProperty
+ *
+ * @param person the person to wrap around
+ * @return an ObjectProperty of the person
+ * @see ObjectProperty
+ */
+ public static ObjectProperty personProperty(Person person) {
+ ObjectProperty property = new ObjectPropertyBase<>() {
+ @Override
+ public Object getBean() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return "";
+ }
+ };
+ property.set(person);
+ return property;
+ }
+
/**
* Returns true if both persons have the same identity and data fields.
* This defines a stronger notion of equality between two persons.
@@ -94,13 +127,14 @@ public boolean equals(Object other) {
&& phone.equals(otherPerson.phone)
&& email.equals(otherPerson.email)
&& address.equals(otherPerson.address)
- && tags.equals(otherPerson.tags);
+ && tags.equals(otherPerson.tags)
+ && notes.equals(otherPerson.notes);
}
@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, address, tags, notes);
}
@Override
@@ -111,6 +145,7 @@ public String toString() {
.add("email", email)
.add("address", address)
.add("tags", tags)
+ .add("notes", notes)
.toString();
}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/bizbook/model/person/Phone.java
similarity index 82%
rename from src/main/java/seedu/address/model/person/Phone.java
rename to src/main/java/bizbook/model/person/Phone.java
index d733f63d739..d23dfd5a503 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/bizbook/model/person/Phone.java
@@ -1,7 +1,7 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.commons.util.AppUtil.checkArgument;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
/**
* Represents a Person's phone number in the address book.
@@ -11,10 +11,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";
- public static final String VALIDATION_REGEX = "\\d{3,}";
+ "Phone numbers should only contain numbers, be 8 digits long and start with 6, 8 or 9";
+ public static final String VALIDATION_REGEX = "^[689]\\d{7}$";
public final String value;
-
/**
* Constructs a {@code Phone}.
*
@@ -57,5 +56,4 @@ public boolean equals(Object other) {
public int hashCode() {
return value.hashCode();
}
-
}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/bizbook/model/person/UniquePersonList.java
similarity index 94%
rename from src/main/java/seedu/address/model/person/UniquePersonList.java
rename to src/main/java/bizbook/model/person/UniquePersonList.java
index cc0a68d79f9..6eb84c89ffc 100644
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ b/src/main/java/bizbook/model/person/UniquePersonList.java
@@ -1,15 +1,15 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.util.Iterator;
import java.util.List;
+import bizbook.model.person.exceptions.DuplicatePersonException;
+import bizbook.model.person.exceptions.PersonNotFoundException;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
/**
* A list of persons that enforces uniqueness between its elements and does not allow nulls.
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/bizbook/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/bizbook/model/person/exceptions/DuplicatePersonException.java
index d7290f59442..9893f760b30 100644
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ b/src/main/java/bizbook/model/person/exceptions/DuplicatePersonException.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person.exceptions;
+package bizbook.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/bizbook/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/bizbook/model/person/exceptions/PersonNotFoundException.java
index fa764426ca7..8db8d340427 100644
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ b/src/main/java/bizbook/model/person/exceptions/PersonNotFoundException.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person.exceptions;
+package bizbook.model.person.exceptions;
/**
* Signals that the operation is unable to find the specified person.
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/bizbook/model/tag/Tag.java
similarity index 93%
rename from src/main/java/seedu/address/model/tag/Tag.java
rename to src/main/java/bizbook/model/tag/Tag.java
index f1a0d4e233b..0952dc09b73 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/bizbook/model/tag/Tag.java
@@ -1,7 +1,7 @@
-package seedu.address.model.tag;
+package bizbook.model.tag;
+import static bizbook.commons.util.AppUtil.checkArgument;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
/**
* Represents a Tag in the address book.
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/bizbook/model/util/SampleDataUtil.java
similarity index 62%
rename from src/main/java/seedu/address/model/util/SampleDataUtil.java
rename to src/main/java/bizbook/model/util/SampleDataUtil.java
index 1806da4facf..3665d8465c6 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/bizbook/model/util/SampleDataUtil.java
@@ -1,42 +1,45 @@
-package seedu.address.model.util;
+package bizbook.model.util;
+import java.util.ArrayList;
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;
+import bizbook.model.AddressBook;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.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")),
+ getTagSet("friends"), getNoteList("High profile client")),
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")),
+ getTagSet("colleagues", "friends"), getNoteList("Likes dumplings")),
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")),
+ getTagSet("neighbours"), getNoteList("Potential return client")),
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")),
+ getTagSet("family"), getNoteList("Owns a manufacturing company")),
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")),
+ getTagSet("classmates"), getNoteList("High profile client")),
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"))
+ getTagSet("colleagues"), getNoteList("Prefers no handshakes"))
};
}
@@ -57,4 +60,13 @@ public static Set getTagSet(String... strings) {
.collect(Collectors.toSet());
}
+ /**
+ * Returns a note set containing the list of strings given.
+ */
+ public static ArrayList getNoteList(String... strings) {
+ return Arrays.stream(strings)
+ .map(Note::new)
+ .collect(Collectors.toCollection(ArrayList::new));
+ }
+
}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/bizbook/storage/AddressBookStorage.java
similarity index 84%
rename from src/main/java/seedu/address/storage/AddressBookStorage.java
rename to src/main/java/bizbook/storage/AddressBookStorage.java
index f2e015105ae..a65b356494a 100644
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ b/src/main/java/bizbook/storage/AddressBookStorage.java
@@ -1,14 +1,15 @@
-package seedu.address.storage;
+package bizbook.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.model.AddressBook;
+import bizbook.model.ReadOnlyAddressBook;
/**
- * Represents a storage for {@link seedu.address.model.AddressBook}.
+ * Represents a storage for {@link AddressBook}.
*/
public interface AddressBookStorage {
@@ -32,6 +33,7 @@ public interface AddressBookStorage {
/**
* Saves the given {@link ReadOnlyAddressBook} to the storage.
+ *
* @param addressBook cannot be null.
* @throws IOException if there was any problem writing to the file.
*/
diff --git a/src/main/java/bizbook/storage/JsonAdaptedNote.java b/src/main/java/bizbook/storage/JsonAdaptedNote.java
new file mode 100644
index 00000000000..d4e23c75462
--- /dev/null
+++ b/src/main/java/bizbook/storage/JsonAdaptedNote.java
@@ -0,0 +1,47 @@
+package bizbook.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.model.person.Note;
+
+/**
+ * Jackson-friendly version of {@link Note}.
+ */
+public class JsonAdaptedNote {
+
+ private final String noteName;
+
+ /**
+ * Constructs a {@code JsonAdaptedNote} with the given {@code noteName}.
+ */
+ @JsonCreator
+ public JsonAdaptedNote(String noteName) {
+ this.noteName = noteName;
+ }
+
+ /**
+ * Converts a given {@code Note} into this class for Jackson use.
+ */
+ public JsonAdaptedNote(Note source) {
+ noteName = source.getNote();
+ }
+
+ @JsonValue
+ public String getNoteName() {
+ return noteName;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted note object into the model's {@code Note} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted note.
+ */
+ public Note toModelType() throws IllegalValueException {
+ if (!Note.isValidNoteName(noteName)) {
+ throw new IllegalValueException(Note.MESSAGE_CONSTRAINTS);
+ }
+ return new Note(noteName);
+ }
+}
diff --git a/src/main/java/bizbook/storage/JsonAdaptedPerson.java b/src/main/java/bizbook/storage/JsonAdaptedPerson.java
new file mode 100644
index 00000000000..f5b060e1bcb
--- /dev/null
+++ b/src/main/java/bizbook/storage/JsonAdaptedPerson.java
@@ -0,0 +1,126 @@
+package bizbook.storage;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
+
+/**
+ * Jackson-friendly version of {@link Person}.
+ */
+class JsonAdaptedPerson {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
+
+ private final String name;
+ private final String phone;
+ private final String email;
+ private final String address;
+ private final List tags = new ArrayList<>();
+ private final List notes = new ArrayList<>();
+
+ /**
+ * 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("tags") List tags, @JsonProperty("notes") List notes) {
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ this.address = address;
+ if (tags != null) {
+ this.tags.addAll(tags);
+ }
+ if (notes != null) {
+ this.notes.addAll(notes);
+ }
+ }
+
+ /**
+ * Converts a given {@code Person} into this class for Jackson use.
+ */
+ public JsonAdaptedPerson(Person source) {
+ name = source.getName().fullName;
+ phone = source.getPhone().value;
+ email = source.getEmail().value;
+ address = source.getAddress().value;
+ tags.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .toList());
+ notes.addAll(source.getNotes().stream()
+ .map(JsonAdaptedNote::new)
+ .toList());
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted person.
+ */
+ public Person toModelType() throws IllegalValueException {
+ final List personTags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tags) {
+ personTags.add(tag.toModelType());
+ }
+
+ final List personNotes = new ArrayList<>();
+ for (JsonAdaptedNote note : notes) {
+ personNotes.add(note.toModelType());
+ }
+
+ final Name modelName = new Name(validateField(name, Name.class.getSimpleName(), Name.MESSAGE_CONSTRAINTS,
+ Name::isValidName));
+ final Phone modelPhone = new Phone(validateField(phone, Phone.class.getSimpleName(), Phone.MESSAGE_CONSTRAINTS,
+ Phone::isValidPhone));
+ final Email modelEmail = new Email(validateField(email, Email.class.getSimpleName(), Email.MESSAGE_CONSTRAINTS,
+ Email::isValidEmail));
+ final Address modelAddress = new Address(validateField(address, Address.class.getSimpleName(),
+ Address.MESSAGE_CONSTRAINTS, Address::isValidAddress));
+
+
+ final Set modelTags = new LinkedHashSet<>(personTags);
+ final ArrayList modelNotes = new ArrayList<>(personNotes);
+
+ return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags, modelNotes);
+ }
+
+ /**
+ * Validates a field based on its presence and provided constraints.
+ *
+ * @param field the field to be validated.
+ * @param fieldName the name of the field that is used for error messages.
+ * @param constraintMessage the message to show if validation fails.
+ * @param isValid a function that checks if the field meets the validation constraints.
+ * @return the validated field value.
+ * @throws IllegalValueException if there were any data constraints violated in the adapted person.
+ */
+ private String validateField(String field, String fieldName, String constraintMessage,
+ Function isValid) throws IllegalValueException {
+ // Check if the field is missing
+ if (field == null) {
+ String errorMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, fieldName);
+ throw new IllegalValueException(errorMessage);
+ }
+
+ // Check if the field violates constraints, if not valid, throw IllegalValueException
+ if (!isValid.apply(field)) {
+ throw new IllegalValueException(constraintMessage);
+ }
+ return field;
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/bizbook/storage/JsonAdaptedTag.java
similarity index 89%
rename from src/main/java/seedu/address/storage/JsonAdaptedTag.java
rename to src/main/java/bizbook/storage/JsonAdaptedTag.java
index 0df22bdb754..c4bf0e9d0a8 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ b/src/main/java/bizbook/storage/JsonAdaptedTag.java
@@ -1,10 +1,10 @@
-package seedu.address.storage;
+package bizbook.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;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.model.tag.Tag;
/**
* Jackson-friendly version of {@link Tag}.
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/bizbook/storage/JsonAddressBookStorage.java
similarity index 86%
rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java
rename to src/main/java/bizbook/storage/JsonAddressBookStorage.java
index 41e06f264e1..b75a630754e 100644
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ b/src/main/java/bizbook/storage/JsonAddressBookStorage.java
@@ -1,4 +1,4 @@
-package seedu.address.storage;
+package bizbook.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.DataLoadingException;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
+import bizbook.commons.core.LogsCenter;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.commons.util.FileUtil;
+import bizbook.commons.util.JsonUtil;
+import bizbook.model.ReadOnlyAddressBook;
/**
* A class to access AddressBook data stored as a json file on the hard disk.
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/bizbook/storage/JsonSerializableAddressBook.java
similarity index 61%
rename from src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
rename to src/main/java/bizbook/storage/JsonSerializableAddressBook.java
index 5efd834091d..4c6c5d92654 100644
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ b/src/main/java/bizbook/storage/JsonSerializableAddressBook.java
@@ -1,4 +1,4 @@
-package seedu.address.storage;
+package bizbook.storage;
import java.util.ArrayList;
import java.util.List;
@@ -8,10 +8,10 @@
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;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.model.AddressBook;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.person.Person;
/**
* An Immutable AddressBook that is serializable to JSON format.
@@ -21,8 +21,14 @@ class JsonSerializableAddressBook {
public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
+ // used to ensure that manually edited data file do not contain unknown person
+ public static final String MESSAGE_DUPLICATE_PIN_PERSON = "Pinned persons list contains duplicate person(s).";
+ public static final String MESSAGE_UNKNOWN_PERSON = "Pinned persons list contains unknown person(s).";
+
private final List persons = new ArrayList<>();
+ private final List pinnedPersons = new ArrayList<>();
+
/**
* Constructs a {@code JsonSerializableAddressBook} with the given persons.
*/
@@ -38,6 +44,8 @@ public JsonSerializableAddressBook(@JsonProperty("persons") List readUserPrefs() throws DataLoadingException {
/**
* Similar to {@link #readUserPrefs()}
+ *
* @param prefsFilePath location of the data. Cannot be null.
* @throws DataLoadingException if the file format is not as expected.
*/
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/bizbook/storage/Storage.java
similarity index 73%
rename from src/main/java/seedu/address/storage/Storage.java
rename to src/main/java/bizbook/storage/Storage.java
index 9fba0c7a1d6..f60a4d40bf2 100644
--- a/src/main/java/seedu/address/storage/Storage.java
+++ b/src/main/java/bizbook/storage/Storage.java
@@ -1,13 +1,13 @@
-package seedu.address.storage;
+package bizbook.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.UserPrefs;
/**
* API of the Storage component
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/bizbook/storage/StorageManager.java
similarity index 89%
rename from src/main/java/seedu/address/storage/StorageManager.java
rename to src/main/java/bizbook/storage/StorageManager.java
index 8b84a9024d5..47ca0db74b9 100644
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ b/src/main/java/bizbook/storage/StorageManager.java
@@ -1,15 +1,15 @@
-package seedu.address.storage;
+package bizbook.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.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import bizbook.commons.core.LogsCenter;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.UserPrefs;
/**
* Manages storage of AddressBook data in local storage.
diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/bizbook/storage/UserPrefsStorage.java
similarity index 69%
rename from src/main/java/seedu/address/storage/UserPrefsStorage.java
rename to src/main/java/bizbook/storage/UserPrefsStorage.java
index e94ca422ea8..654a9760507 100644
--- a/src/main/java/seedu/address/storage/UserPrefsStorage.java
+++ b/src/main/java/bizbook/storage/UserPrefsStorage.java
@@ -1,15 +1,15 @@
-package seedu.address.storage;
+package bizbook.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.UserPrefs;
/**
- * Represents a storage for {@link seedu.address.model.UserPrefs}.
+ * Represents a storage for {@link UserPrefs}.
*/
public interface UserPrefsStorage {
@@ -27,7 +27,8 @@ public interface UserPrefsStorage {
Optional readUserPrefs() throws DataLoadingException;
/**
- * Saves the given {@link seedu.address.model.ReadOnlyUserPrefs} to the storage.
+ * Saves the given {@link 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/bizbook/ui/CommandBox.java
similarity index 62%
rename from src/main/java/seedu/address/ui/CommandBox.java
rename to src/main/java/bizbook/ui/CommandBox.java
index 9e75478664b..a8a36005d93 100644
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ b/src/main/java/bizbook/ui/CommandBox.java
@@ -1,12 +1,12 @@
-package seedu.address.ui;
+package bizbook.ui;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.exceptions.ParseException;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
+import javafx.scene.input.KeyEvent;
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;
/**
* The UI component that is responsible for receiving user command inputs.
@@ -17,16 +17,19 @@ public class CommandBox extends UiPart {
private static final String FXML = "CommandBox.fxml";
private final CommandExecutor commandExecutor;
+ private final CommandHistory commandHistory;
@FXML
private TextField commandTextField;
/**
- * Creates a {@code CommandBox} with the given {@code CommandExecutor}.
+ * Creates a {@code CommandBox} with the given {@code CommandExecutor} and {@code CommandHistory}.
*/
- public CommandBox(CommandExecutor commandExecutor) {
+ public CommandBox(CommandExecutor commandExecutor, CommandHistory commandHistory) {
super(FXML);
this.commandExecutor = commandExecutor;
+ this.commandHistory = commandHistory;
+
// calls #setStyleToDefault() whenever there is a change to the text of the command box.
commandTextField.textProperty().addListener((unused1, unused2, unused3) -> setStyleToDefault());
}
@@ -44,11 +47,37 @@ private void handleCommandEntered() {
try {
commandExecutor.execute(commandText);
commandTextField.setText("");
+ commandHistory.addCommand(commandText);
} catch (CommandException | ParseException e) {
setStyleToIndicateCommandFailure();
}
}
+ /**
+ * Populates command box with {@param text}.
+ */
+ private void autoCompleteText(String text) {
+ commandTextField.setText(text);
+ commandTextField.positionCaret(commandTextField.getText().length()); // Move cursor to end
+ }
+
+ /**
+ * Handles the key press event, {@code KeyEvent}.
+ */
+ @FXML
+ private void handleKeyPressed(KeyEvent keyEvent) {
+ switch (keyEvent.getCode()) {
+ case UP:
+ autoCompleteText(commandHistory.getPreviousCommand());
+ break;
+ case DOWN:
+ autoCompleteText(commandHistory.getNextCommand());
+ break;
+ default:
+ break;
+ }
+ }
+
/**
* Sets the command box style to use the default style.
*/
@@ -68,18 +97,4 @@ private void setStyleToIndicateCommandFailure() {
styleClass.add(ERROR_STYLE_CLASS);
}
-
- /**
- * Represents a function that can execute commands.
- */
- @FunctionalInterface
- public interface CommandExecutor {
- /**
- * Executes the command and returns the result.
- *
- * @see seedu.address.logic.Logic#execute(String)
- */
- CommandResult execute(String commandText) throws CommandException, ParseException;
- }
-
}
diff --git a/src/main/java/bizbook/ui/CommandExecutor.java b/src/main/java/bizbook/ui/CommandExecutor.java
new file mode 100644
index 00000000000..82bb9c09800
--- /dev/null
+++ b/src/main/java/bizbook/ui/CommandExecutor.java
@@ -0,0 +1,18 @@
+package bizbook.ui;
+
+import bizbook.logic.Logic;
+import bizbook.logic.commands.CommandResult;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.exceptions.ParseException;
+/**
+ * Represents a function that can execute commands.
+ */
+@FunctionalInterface
+public interface CommandExecutor {
+ /**
+ * Executes the command and returns the result.
+ *
+ * @see Logic#execute(String)
+ */
+ CommandResult execute(String commandText) throws CommandException, ParseException;
+}
diff --git a/src/main/java/bizbook/ui/CommandHistory.java b/src/main/java/bizbook/ui/CommandHistory.java
new file mode 100644
index 00000000000..1153e2bc9bc
--- /dev/null
+++ b/src/main/java/bizbook/ui/CommandHistory.java
@@ -0,0 +1,63 @@
+package bizbook.ui;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+
+/**
+ * Manages the command history for the CommandBox.
+ */
+public class CommandHistory {
+ private ObservableList history;
+ private int currentIndex;
+
+ /**
+ * Creates a {@code CommandHistory} to store command history.
+ */
+ public CommandHistory() {
+ history = FXCollections.observableArrayList();
+ currentIndex = -1;
+ }
+
+ /**
+ * Adds a new command to the history.
+ *
+ * @param command the command to add.
+ * */
+ public void addCommand(String command) {
+ history.add(command);
+ currentIndex = history.size(); // Set to after the last command
+ }
+
+ /**
+ * Gets the previous command in the history.
+ *
+ * @return the previous command, or an empty string if at the beginning of the history.
+ */
+ public String getPreviousCommand() {
+ if (currentIndex > 0) {
+ currentIndex--;
+ return history.get(currentIndex);
+ }
+ return "";
+ }
+
+ /**
+ * Gets the next command in the history.
+ *
+ * @return the next command, or an empty string if at the end of the history
+ */
+ public String getNextCommand() {
+ if (currentIndex >= 0 && currentIndex < history.size()) {
+ return history.get(currentIndex++);
+ }
+ return "";
+ }
+
+ /**
+ * Clears the command history.
+ */
+ public void clear() {
+ history.clear();
+ currentIndex = -1;
+ }
+}
diff --git a/src/main/java/bizbook/ui/CommandTablePanel.java b/src/main/java/bizbook/ui/CommandTablePanel.java
new file mode 100644
index 00000000000..d7c93020f6a
--- /dev/null
+++ b/src/main/java/bizbook/ui/CommandTablePanel.java
@@ -0,0 +1,177 @@
+package bizbook.ui;
+
+import java.util.logging.Logger;
+
+import bizbook.commons.core.LogsCenter;
+import bizbook.logic.commands.AddCommand;
+import bizbook.logic.commands.AddNoteCommand;
+import bizbook.logic.commands.ClearCommand;
+import bizbook.logic.commands.DeleteCommand;
+import bizbook.logic.commands.DeleteNoteCommand;
+import bizbook.logic.commands.DeleteTagCommand;
+import bizbook.logic.commands.EditCommand;
+import bizbook.logic.commands.EditNoteCommand;
+import bizbook.logic.commands.ExitCommand;
+import bizbook.logic.commands.ExportCommand;
+import bizbook.logic.commands.FindCommand;
+import bizbook.logic.commands.HelpCommand;
+import bizbook.logic.commands.ImportCommand;
+import bizbook.logic.commands.ListCommand;
+import bizbook.logic.commands.PinCommand;
+import bizbook.logic.commands.RedoCommand;
+import bizbook.logic.commands.ToggleCommand;
+import bizbook.logic.commands.UndoCommand;
+import bizbook.logic.commands.UnpinCommand;
+import bizbook.logic.commands.ViewCommand;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.TableCell;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.Region;
+import javafx.scene.text.Text;
+
+/**
+ * Panel containing the list of command help.
+ */
+public class CommandTablePanel extends UiPart {
+ private static final String FXML = "CommandTablePanel.fxml";
+
+ private static final double COMMAND_WORD_RATIO = 0.15;
+ private static final double COMMAND_USAGE_RATIO = 0.85;
+
+ private static final double COMMAND_WORD_COLUMN_SIZE = Integer.MAX_VALUE * COMMAND_WORD_RATIO;
+ private static final double COMMAND_USAGE_COLUMN_SIZE = Integer.MAX_VALUE * COMMAND_USAGE_RATIO;
+
+ private final Logger logger = LogsCenter.getLogger(CommandTablePanel.class);
+
+
+ @FXML
+ private TableView commandTable;
+
+ @FXML
+ private TableColumn actionColumn;
+
+ @FXML
+ private TableColumn formatColumn;
+
+ /**
+ * Creates a {@code CommandTablePanel}
+ */
+ public CommandTablePanel() {
+ super(FXML);
+ initializeTable();
+ populateData();
+ }
+
+ /**
+ * Initialize table formatting.
+ */
+ private void initializeTable() {
+ commandTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+
+ actionColumn.setCellValueFactory(new PropertyValueFactory<>("commandWord"));
+ actionColumn.setMaxWidth(COMMAND_WORD_COLUMN_SIZE);
+ actionColumn.setMinWidth(75);
+
+ formatColumn.setCellValueFactory(new PropertyValueFactory<>("commandUsage"));
+ formatColumn.setCellFactory(column -> new CommandTableCell());
+ formatColumn.setMinWidth(100);
+ formatColumn.setMaxWidth(COMMAND_USAGE_COLUMN_SIZE);
+
+ commandTable.widthProperty().addListener((obs, oldWidth, newWidth) -> {
+ actionColumn.setPrefWidth(newWidth.doubleValue() * COMMAND_WORD_RATIO);
+ formatColumn.setPrefWidth(newWidth.doubleValue() * COMMAND_USAGE_COLUMN_SIZE);
+ });
+ }
+
+ /**
+ * Fills up the table with the commands.
+ */
+ private void populateData() {
+ logger.fine("Showing a few command format of the application.");
+ ObservableList commandList = FXCollections.observableArrayList(
+ // Add more commands here as needed
+ new CommandEntry(AddCommand.COMMAND_WORD, AddCommand.MESSAGE_USAGE),
+ new CommandEntry(AddNoteCommand.COMMAND_WORD, AddNoteCommand.MESSAGE_USAGE),
+ new CommandEntry(ClearCommand.COMMAND_WORD, ClearCommand.MESSAGE_USAGE),
+ new CommandEntry(DeleteCommand.COMMAND_WORD, DeleteCommand.MESSAGE_USAGE),
+ new CommandEntry(DeleteNoteCommand.COMMAND_WORD, DeleteNoteCommand.MESSAGE_USAGE),
+ new CommandEntry(DeleteTagCommand.COMMAND_WORD, DeleteTagCommand.MESSAGE_USAGE),
+ new CommandEntry(EditCommand.COMMAND_WORD, EditCommand.MESSAGE_USAGE),
+ new CommandEntry(EditNoteCommand.COMMAND_WORD, EditNoteCommand.MESSAGE_USAGE),
+ new CommandEntry(ExitCommand.COMMAND_WORD, ExitCommand.MESSAGE_USAGE),
+ new CommandEntry(ExportCommand.COMMAND_WORD, ExportCommand.MESSAGE_USAGE),
+ new CommandEntry(FindCommand.COMMAND_WORD, FindCommand.MESSAGE_USAGE),
+ new CommandEntry(HelpCommand.COMMAND_WORD, HelpCommand.MESSAGE_USAGE),
+ new CommandEntry(ImportCommand.COMMAND_WORD, ImportCommand.MESSAGE_USAGE),
+ new CommandEntry(ListCommand.COMMAND_WORD, ListCommand.MESSAGE_USAGE),
+ new CommandEntry(PinCommand.COMMAND_WORD, PinCommand.MESSAGE_USAGE),
+ new CommandEntry(RedoCommand.COMMAND_WORD, RedoCommand.MESSAGE_USAGE),
+ new CommandEntry(ToggleCommand.COMMAND_WORD, ToggleCommand.MESSAGE_USAGE),
+ new CommandEntry(UndoCommand.COMMAND_WORD, UndoCommand.MESSAGE_USAGE),
+ new CommandEntry(UnpinCommand.COMMAND_WORD, UnpinCommand.MESSAGE_USAGE),
+ new CommandEntry(ViewCommand.COMMAND_WORD, ViewCommand.MESSAGE_USAGE)
+ );
+ commandTable.setItems(commandList);
+ }
+
+ /**
+ * Custom table record that displays onto table.
+ */
+ public class CommandEntry {
+ private String commandWord;
+ private String commandUsage;
+
+ /**
+ * Creates a {@code CommandEntry} with the given command word and usage string.
+ */
+ public CommandEntry(String commandWord, String commandUsage) {
+ this.commandWord = commandWord;
+ this.commandUsage = commandUsage;
+ }
+
+ /**
+ * Gets the command word.
+ *
+ * @return command word.
+ */
+ public String getCommandWord() {
+ return this.commandWord;
+ }
+
+ /**
+ * Gets the command usage syntax.
+ *
+ * @return command usage.
+ */
+ public String getCommandUsage() {
+ return this.commandUsage;
+ }
+ }
+
+ /**
+ * Custom {@code TableCell} that displays the graphics of a command record.
+ */
+ class CommandTableCell extends TableCell {
+ private final Text text = new Text();
+
+ @Override
+ protected void updateItem(String item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty || item == null) {
+ setGraphic(null);
+ } else {
+ text.setText(item);
+
+ text.wrappingWidthProperty()
+ .bind(getTableColumn().widthProperty().subtract(10));
+ text.getStyleClass().add("help-textbox");
+ text.setId("help-textbox");
+ setGraphic(text);
+ }
+ }
+ };
+}
diff --git a/src/main/java/bizbook/ui/ContactDetails.java b/src/main/java/bizbook/ui/ContactDetails.java
new file mode 100644
index 00000000000..8935b35faaa
--- /dev/null
+++ b/src/main/java/bizbook/ui/ContactDetails.java
@@ -0,0 +1,99 @@
+package bizbook.ui;
+
+import java.util.logging.Logger;
+
+import bizbook.commons.core.LogsCenter;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+
+/**
+ * Controller for the contact details panel.
+ */
+public class ContactDetails extends UiPart {
+
+ private static final String FXML = "ContactDetails.fxml";
+ private final Logger logger = LogsCenter.getLogger(ContactDetails.class);
+
+ @FXML
+ private ScrollPane contactDetailsPanel;
+
+ @FXML
+ private Label name;
+
+ @FXML
+ private Label phoneNo;
+
+ @FXML
+ private Label email;
+
+ @FXML
+ private Label address;
+
+ @FXML
+ private Label notes;
+
+ @FXML
+ private VBox notesList;
+
+ /**
+ * Creates a {@code ContactDetailsPanel} with the given {@code Person} information.
+ */
+ public ContactDetails(ObjectProperty person) {
+ super(FXML);
+ person.addListener((observable, oldValue, newValue) -> displayPerson(newValue));
+ }
+
+ /**
+ * Sets the person object as the contact to be displayed on the panel.
+ *
+ * @param person The person object to be updated onto the panel.
+ */
+ private void displayPerson(Person person) {
+ clearPanel();
+
+ if (person == null || person.equals(null)) {
+ return;
+ }
+
+ logger.info("Displaying info of " + person.toString());
+
+ name.setText(person.getName().fullName);
+ phoneNo.setText("Mobile: " + person.getPhone().toString());
+ email.setText("Email: " + person.getEmail().toString());
+ address.setText("Address: " + person.getAddress().toString());
+
+ if (!person.getNotes().isEmpty()) {
+ Label notesHeader = new Label("Notes");
+ notesHeader.setId("notes-header");
+ notesList.getChildren().add(notesHeader);
+ }
+
+ int index = 1;
+ for (Note note : person.getNotes()) {
+ Label label = new Label(index + ". " + note.getNote());
+ label.setId("notes-label");
+ notesList.getChildren().add(label);
+
+ index++;
+ }
+ }
+
+ /**
+ * Clears any previous contact details from the panel.
+ */
+ private void clearPanel() {
+ // Clear existing labels
+ name.setText("");
+ phoneNo.setText("");
+ email.setText("");
+ address.setText("");
+ notes.setText("");
+ notesList.getChildren().clear();
+ }
+}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/bizbook/ui/HelpWindow.java
similarity index 51%
rename from src/main/java/seedu/address/ui/HelpWindow.java
rename to src/main/java/bizbook/ui/HelpWindow.java
index 3f16b2fcf26..6554c79c9ac 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/bizbook/ui/HelpWindow.java
@@ -1,32 +1,44 @@
-package seedu.address.ui;
+package bizbook.ui;
+import java.awt.Desktop;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.logging.Logger;
+import bizbook.commons.core.LogsCenter;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
+import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
-import seedu.address.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_URL = "https://ay2425s1-cs2103-f10-3.github.io/tp/UserGuide.html";
+ public static final String HELP_MESSAGE = "For full details, refer to the user guide: " + USERGUIDE_URL;
+ public static final String URL_FAIL_MESSAGE = "Failed to open the URL. The URL has been copied to the clipboard.";
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";
+ private CommandTablePanel commandTablePanel;
@FXML
private Button copyButton;
+ @FXML
+ private Label errorMessageLabel;
+
@FXML
private Label helpMessage;
+ @FXML
+ private StackPane commandTablePlaceholder;
+
/**
* Creates a new HelpWindow.
*
@@ -35,6 +47,8 @@ public class HelpWindow extends UiPart {
public HelpWindow(Stage root) {
super(FXML, root);
helpMessage.setText(HELP_MESSAGE);
+ errorMessageLabel.setText("");
+ errorMessageLabel.setManaged(false);
}
/**
@@ -46,6 +60,7 @@ public HelpWindow() {
/**
* Shows the help window.
+ *
* @throws IllegalStateException
*
*
@@ -90,13 +105,64 @@ public void focus() {
}
/**
- * Copies the URL to the user guide to the clipboard.
+ * Handles the URL button pressed event.
*/
@FXML
+ private void handleUrl() {
+ // try to open browser
+ boolean redirectSuccess = openUrl();
+
+ // fall back to copying URL to clipboard
+ if (!redirectSuccess) {
+ copyUrl();
+ showError();
+ }
+ }
+
+ /**
+ * Makes error message appear.
+ */
+ private void showError() {
+ errorMessageLabel.setText(URL_FAIL_MESSAGE);
+ errorMessageLabel.setManaged(true);
+ this.getRoot().sizeToScene();
+ }
+
+
+ /**
+ * Copies the URL to the user guide to the clipboard.
+ */
private void copyUrl() {
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent url = new ClipboardContent();
url.putString(USERGUIDE_URL);
clipboard.setContent(url);
}
+
+ /**
+ * Open the URL to the user guide to the clipboard.
+ *
+ * @return success status of URL open.
+ */
+ private boolean openUrl() {
+ try {
+ if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
+ Desktop.getDesktop().browse(new URI(USERGUIDE_URL));
+ return true;
+ } else {
+ System.out.println("Desktop browsing is not supported on this system.");
+ }
+ } catch (IOException | URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ /**
+ * Fills up all the placeholders of this window.
+ */
+ void fillInnerParts() {
+ commandTablePanel = new CommandTablePanel();
+ commandTablePlaceholder.getChildren().add(commandTablePanel.getRoot());
+ }
}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/bizbook/ui/MainWindow.java
similarity index 60%
rename from src/main/java/seedu/address/ui/MainWindow.java
rename to src/main/java/bizbook/ui/MainWindow.java
index 79e74ef37c0..e23f5cee2d9 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/bizbook/ui/MainWindow.java
@@ -1,21 +1,23 @@
-package seedu.address.ui;
+package bizbook.ui;
import java.util.logging.Logger;
+import bizbook.commons.core.GuiSettings;
+import bizbook.commons.core.LogsCenter;
+import bizbook.logic.Logic;
+import bizbook.logic.commands.CommandResult;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.exceptions.ParseException;
+import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
+import javafx.scene.Scene;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputControl;
import javafx.scene.input.KeyCombination;
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;
/**
* The Main Window. Provides the basic application layout containing
@@ -24,32 +26,57 @@
public class MainWindow extends UiPart {
private static final String FXML = "MainWindow.fxml";
+ private static final String DARK_THEME_URL = MainWindow.class.getResource("/view/DarkTheme.css").toExternalForm();
+ private static final String LIGHT_THEME_URL = MainWindow.class.getResource("/view/LightTheme.css").toExternalForm();
+ private static final String DARK_THEME_HELP_URL =
+ MainWindow.class.getResource("/view/HelpWindowDark.css").toExternalForm();
+ private static final String LIGHT_THEME_HELP_URL =
+ MainWindow.class.getResource("/view/HelpWindowLight.css").toExternalForm();
+
+ private boolean isDarkTheme = true;
+ private Scene scene;
private final Logger logger = LogsCenter.getLogger(getClass());
private Stage primaryStage;
private Logic logic;
+ private CommandHistory commandHistory;
// Independent Ui parts residing in this Ui container
private PersonListPanel personListPanel;
+ private PinnedPersonListPanel pinnedPersonListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
+ private ContactDetails contactDetailsPanel;
+ private SearchBox searchBox;
+
+ @FXML
+ private MenuItem toggleThemeMenuItem;
@FXML
private StackPane commandBoxPlaceholder;
+ @FXML
+ private StackPane searchBoxPlaceholder;
+
@FXML
private MenuItem helpMenuItem;
@FXML
private StackPane personListPanelPlaceholder;
+ @FXML
+ private StackPane pinnedListPanelPlaceholder;
+
@FXML
private StackPane resultDisplayPlaceholder;
@FXML
private StackPane statusbarPlaceholder;
+ @FXML
+ private StackPane contactDetailsPanelPlaceholder;
+
/**
* Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}.
*/
@@ -59,6 +86,8 @@ public MainWindow(Stage primaryStage, Logic logic) {
// Set dependencies
this.primaryStage = primaryStage;
this.logic = logic;
+ this.commandHistory = new CommandHistory();
+ this.scene = getRoot().getScene();
// Configure the UI
setWindowDefaultSize(logic.getGuiSettings());
@@ -78,6 +107,7 @@ private void setAccelerators() {
/**
* Sets the accelerator of a MenuItem.
+ *
* @param keyCombination the KeyCombination value of the accelerator
*/
private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
@@ -110,17 +140,27 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
+
+ contactDetailsPanel = new ContactDetails(logic.getFocusedPerson());
+ contactDetailsPanelPlaceholder.getChildren().add(contactDetailsPanel.getRoot());
+
+ personListPanel = new PersonListPanel(logic.getFilteredPersonList(), logic.getFocusedPerson());
personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ pinnedPersonListPanel = new PinnedPersonListPanel(logic.getPinnedPersonList(), logic.getFocusedPerson());
+ pinnedListPanelPlaceholder.getChildren().add(pinnedPersonListPanel.getRoot());
+
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath());
statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot());
- CommandBox commandBox = new CommandBox(this::executeCommand);
+ CommandBox commandBox = new CommandBox(this::executeCommand, commandHistory);
commandBoxPlaceholder.getChildren().add(commandBox.getRoot());
+
+ searchBox = new SearchBox(this::executeFindCommand);
+ searchBoxPlaceholder.getChildren().add(searchBox.getRoot());
}
/**
@@ -141,6 +181,7 @@ private void setWindowDefaultSize(GuiSettings guiSettings) {
@FXML
public void handleHelp() {
if (!helpWindow.isShowing()) {
+ helpWindow.fillInnerParts();
helpWindow.show();
} else {
helpWindow.focus();
@@ -162,15 +203,37 @@ private void handleExit() {
helpWindow.hide();
primaryStage.hide();
}
+ /**
+ * Toggles between light and dark themes
+ */
+ @FXML
+ private void handleThemeChange() {
+ isDarkTheme = !isDarkTheme;
+
+ // Get the scene's stylesheets
+ ObservableList stylesheets = scene.getStylesheets();
+ ObservableList helpStylesheets = helpWindow.getRoot().getScene().getStylesheets();
+ stylesheets.clear();
+ helpStylesheets.clear();
+
+ // Add the appropriate stylesheet based on the theme
+ if (isDarkTheme) {
+ stylesheets.add(DARK_THEME_URL);
+ helpStylesheets.add(DARK_THEME_HELP_URL);
+ toggleThemeMenuItem.setText("Switch to Light Theme");
+ } else {
+ stylesheets.add(LIGHT_THEME_URL);
+ helpStylesheets.add(LIGHT_THEME_HELP_URL);
+ toggleThemeMenuItem.setText("Switch to Dark Theme");
+ }
- public PersonListPanel getPersonListPanel() {
- return personListPanel;
+ logger.info("Theme switched to " + (isDarkTheme ? "dark" : "light") + " mode");
}
/**
* Executes the command and returns the result.
*
- * @see seedu.address.logic.Logic#execute(String)
+ * @see Logic#execute(String)
*/
private CommandResult executeCommand(String commandText) throws CommandException, ParseException {
try {
@@ -186,6 +249,12 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleExit();
}
+ if (commandResult.isThemeChange()) {
+ handleThemeChange();
+ }
+
+ searchBox.clearSearchBox();
+
return commandResult;
} catch (CommandException | ParseException e) {
logger.info("An error occurred while executing command: " + commandText);
@@ -193,4 +262,21 @@ private CommandResult executeCommand(String commandText) throws CommandException
throw e;
}
}
+
+ /**
+ * Executes the find command and returns the result.
+ *
+ * @see Logic#execute(String)
+ */
+ private CommandResult executeFindCommand(String commandText) throws CommandException, ParseException {
+ try {
+ CommandResult commandResult = logic.execute(commandText);
+ logger.info("Result: " + commandResult.getFeedbackToUser());
+
+ return commandResult;
+ } catch (CommandException | ParseException e) {
+ logger.info("An error occurred while executing command: " + commandText);
+ throw e;
+ }
+ }
}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/bizbook/ui/PersonCard.java
similarity index 82%
rename from src/main/java/seedu/address/ui/PersonCard.java
rename to src/main/java/bizbook/ui/PersonCard.java
index 094c42cda82..6cd3e2308d2 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/bizbook/ui/PersonCard.java
@@ -1,16 +1,16 @@
-package seedu.address.ui;
+package bizbook.ui;
import java.util.Comparator;
+import bizbook.model.person.Person;
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;
/**
- * An UI component that displays information of a {@code Person}.
+ * A UI component that displays information of a {@code Person}.
*/
public class PersonCard extends UiPart {
@@ -35,10 +35,6 @@ public class PersonCard extends UiPart {
@FXML
private Label phone;
@FXML
- private Label address;
- @FXML
- private Label email;
- @FXML
private FlowPane tags;
/**
@@ -50,8 +46,6 @@ 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)));
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/bizbook/ui/PersonListPanel.java
similarity index 55%
rename from src/main/java/seedu/address/ui/PersonListPanel.java
rename to src/main/java/bizbook/ui/PersonListPanel.java
index f4c501a897b..c18c2ab6dd3 100644
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ b/src/main/java/bizbook/ui/PersonListPanel.java
@@ -1,14 +1,16 @@
-package seedu.address.ui;
+package bizbook.ui;
import java.util.logging.Logger;
+import bizbook.commons.core.LogsCenter;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
+import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
/**
* Panel containing the list of persons.
@@ -23,10 +25,29 @@ public class PersonListPanel extends UiPart {
/**
* Creates a {@code PersonListPanel} with the given {@code ObservableList}.
*/
- public PersonListPanel(ObservableList personList) {
+ public PersonListPanel(ObservableList personList, ObjectProperty focusedPerson) {
super(FXML);
personListView.setItems(personList);
personListView.setCellFactory(listView -> new PersonListViewCell());
+
+ // Add event handler
+ personListView.setOnMouseClicked(event -> handleListViewClick(event, focusedPerson));
+ }
+
+ /**
+ * When user clicks on a person, the details plane changes.
+ */
+ private void handleListViewClick(MouseEvent event, ObjectProperty focusedPerson) {
+ // Get the index of the clicked item
+ int index = personListView.getSelectionModel().getSelectedIndex();
+ Person selectedPerson = personListView.getSelectionModel().getSelectedItem();
+
+ if (index != -1) {
+ focusedPerson.set(selectedPerson);
+ logger.info("Clicked on person: " + selectedPerson + " at index " + index);
+ } else {
+ logger.info("Clicked on an empty area of the ListView");
+ }
}
/**
diff --git a/src/main/java/bizbook/ui/PinnedPersonCard.java b/src/main/java/bizbook/ui/PinnedPersonCard.java
new file mode 100644
index 00000000000..79df4a4872d
--- /dev/null
+++ b/src/main/java/bizbook/ui/PinnedPersonCard.java
@@ -0,0 +1,41 @@
+package bizbook.ui;
+
+import java.util.Comparator;
+
+import bizbook.model.person.Person;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+
+/**
+ * A UI component that displays information of a {@code PinnedPerson}.
+ */
+public class PinnedPersonCard extends UiPart {
+ private static final String FXML = "PinnedPersonCard.fxml";
+
+ @FXML
+ private VBox cardPane;
+ @FXML
+ private Label id;
+ @FXML
+ private Label name;
+ @FXML
+ private Label phone;
+ @FXML
+ private FlowPane tags;
+
+ /**
+ * Creates a {@code PersonCode} with the given {@code Person} and index to display.
+ */
+ public PinnedPersonCard(Person person, int displayedIndex) {
+ super(FXML);
+ id.setText(displayedIndex + ". ");
+ name.setText(person.getName().fullName);
+ phone.setText(person.getPhone().value);
+ person.getTags().stream()
+ .sorted(Comparator.comparing(tag -> tag.tagName))
+ .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+ }
+}
diff --git a/src/main/java/bizbook/ui/PinnedPersonListPanel.java b/src/main/java/bizbook/ui/PinnedPersonListPanel.java
new file mode 100644
index 00000000000..4afddc8baa3
--- /dev/null
+++ b/src/main/java/bizbook/ui/PinnedPersonListPanel.java
@@ -0,0 +1,68 @@
+package bizbook.ui;
+
+import java.util.logging.Logger;
+
+import bizbook.commons.core.LogsCenter;
+import bizbook.model.person.Person;
+import javafx.beans.property.ObjectProperty;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Region;
+
+/**
+ * Panel containing the list of pinned persons.
+ */
+public class PinnedPersonListPanel extends UiPart {
+ private static final String FXML = "PinnedPersonListPanel.fxml";
+ private static final Integer INITIAL_INDEX_VALUE = -1;
+ private final Logger logger = LogsCenter.getLogger(PinnedPersonListPanel.class);
+
+
+ @FXML
+ private ListView pinnedPersonListView;
+
+ /**
+ * Creates a {@code PinnedPersonListPanel} with the given {@code ObservableList}.
+ */
+ public PinnedPersonListPanel(ObservableList pinnedPersonList, ObjectProperty focusedPerson) {
+ super(FXML);
+
+ pinnedPersonListView.setItems(pinnedPersonList);
+ pinnedPersonListView.setCellFactory(listView -> new PinnedPersonListViewCell());
+
+ // Add event handler
+ pinnedPersonListView.setOnMouseClicked(event -> handleListViewClick(event, focusedPerson));
+ }
+
+ private void handleListViewClick(MouseEvent event, ObjectProperty focusedPerson) {
+ int index = pinnedPersonListView.getSelectionModel().getSelectedIndex();
+ Person selectedPerson = pinnedPersonListView.getSelectionModel().getSelectedItem();
+
+ if (index != INITIAL_INDEX_VALUE) {
+ focusedPerson.set(selectedPerson);
+ logger.info("Clicked on pinned person: " + selectedPerson + " at index " + index);
+ } else {
+ logger.info("Clicked on an empty area of the PinnedListView");
+ }
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PinnedPersonCard}.
+ */
+ class PinnedPersonListViewCell 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 PinnedPersonCard(person, getIndex() + 1).getRoot());
+ }
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/bizbook/ui/ResultDisplay.java
similarity index 95%
rename from src/main/java/seedu/address/ui/ResultDisplay.java
rename to src/main/java/bizbook/ui/ResultDisplay.java
index 7d98e84eedf..f896f5df7c8 100644
--- a/src/main/java/seedu/address/ui/ResultDisplay.java
+++ b/src/main/java/bizbook/ui/ResultDisplay.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package bizbook.ui;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/bizbook/ui/SearchBox.java b/src/main/java/bizbook/ui/SearchBox.java
new file mode 100644
index 00000000000..f39e6246d81
--- /dev/null
+++ b/src/main/java/bizbook/ui/SearchBox.java
@@ -0,0 +1,74 @@
+package bizbook.ui;
+
+import bizbook.logic.commands.FindCommand;
+import bizbook.logic.commands.ListCommand;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.exceptions.ParseException;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.fxml.FXML;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.Region;
+
+/**
+ * The UI component that is responsible for receiving find command
+ * without requiring command word.
+ */
+public class SearchBox extends UiPart {
+
+ private static final String FXML = "SearchBox.fxml";
+
+ private final CommandExecutor commandExecutor;
+ private final ChangeListener searchBoxChangeListener;
+
+ @FXML
+ private TextField searchBoxField;
+
+ /**
+ * Creates a {@code SearchBox} with the given {@code CommandExecutor}.
+ */
+ public SearchBox(CommandExecutor commandExecutor) {
+ super(FXML);
+ this.commandExecutor = commandExecutor;
+ searchBoxChangeListener = new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue) {
+ handleCommandUpdate();
+ }
+ };
+ searchBoxField.textProperty().addListener(searchBoxChangeListener);
+ }
+
+ /**
+ * Handles the text field being updated.
+ */
+ @FXML
+ private void handleCommandUpdate() {
+ String commandText = searchBoxField.getText();
+
+ if (commandText.isEmpty()) {
+ try {
+ commandExecutor.execute(ListCommand.COMMAND_WORD);
+ } catch (CommandException | ParseException e) {
+ return;
+ }
+ }
+
+ try {
+ commandExecutor.execute(String.format("%s %s",
+ FindCommand.COMMAND_WORD, commandText));
+ } catch (CommandException | ParseException e) {
+ return;
+ }
+ }
+
+ /**
+ * Clears search box input.
+ */
+ public void clearSearchBox() {
+ // temporarily disable listener before clearing field
+ searchBoxField.textProperty().removeListener(searchBoxChangeListener);
+ searchBoxField.setText("");
+ searchBoxField.textProperty().addListener(searchBoxChangeListener);
+ }
+}
diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/bizbook/ui/StatusBarFooter.java
similarity index 96%
rename from src/main/java/seedu/address/ui/StatusBarFooter.java
rename to src/main/java/bizbook/ui/StatusBarFooter.java
index b577f829423..8db428c3df2 100644
--- a/src/main/java/seedu/address/ui/StatusBarFooter.java
+++ b/src/main/java/bizbook/ui/StatusBarFooter.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package bizbook.ui;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/bizbook/ui/Ui.java
similarity index 86%
rename from src/main/java/seedu/address/ui/Ui.java
rename to src/main/java/bizbook/ui/Ui.java
index 17aa0b494fe..9c90292f675 100644
--- a/src/main/java/seedu/address/ui/Ui.java
+++ b/src/main/java/bizbook/ui/Ui.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package bizbook.ui;
import javafx.stage.Stage;
diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/bizbook/ui/UiManager.java
similarity index 91%
rename from src/main/java/seedu/address/ui/UiManager.java
rename to src/main/java/bizbook/ui/UiManager.java
index fdf024138bc..56ab7bd241b 100644
--- a/src/main/java/seedu/address/ui/UiManager.java
+++ b/src/main/java/bizbook/ui/UiManager.java
@@ -1,16 +1,16 @@
-package seedu.address.ui;
+package bizbook.ui;
import java.util.logging.Logger;
+import bizbook.MainApp;
+import bizbook.commons.core.LogsCenter;
+import bizbook.commons.util.StringUtil;
+import bizbook.logic.Logic;
import javafx.application.Platform;
import javafx.scene.control.Alert;
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;
/**
* 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/BizBook.png";
private Logic logic;
private MainWindow mainWindow;
diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/bizbook/ui/UiPart.java
similarity index 97%
rename from src/main/java/seedu/address/ui/UiPart.java
rename to src/main/java/bizbook/ui/UiPart.java
index fc820e01a9c..169a237b4de 100644
--- a/src/main/java/seedu/address/ui/UiPart.java
+++ b/src/main/java/bizbook/ui/UiPart.java
@@ -1,12 +1,12 @@
-package seedu.address.ui;
+package bizbook.ui;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.net.URL;
+import bizbook.MainApp;
import javafx.fxml.FXMLLoader;
-import seedu.address.MainApp;
/**
* Represents a distinct part of the UI. e.g. Windows, dialogs, panels, status bars, etc.
@@ -29,6 +29,7 @@ public UiPart(URL fxmlFileUrl) {
/**
* Constructs a UiPart using the specified FXML file within {@link #FXML_FILE_FOLDER}.
+ *
* @see #UiPart(URL)
*/
public UiPart(String fxmlFileName) {
@@ -45,6 +46,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)
*/
public UiPart(String fxmlFileName, T root) {
@@ -60,6 +62,7 @@ public T getRoot() {
/**
* Loads the object hierarchy from a FXML document.
+ *
* @param location Location of the FXML document.
* @param root Specifies the root of the object hierarchy.
*/
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 3149ee07e0b..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
-
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import seedu.address.commons.core.LogsCenter;
-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+)(?.*)");
- private static final Logger logger = LogsCenter.getLogger(AddressBookParser.class);
-
- /**
- * 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");
-
- // Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
- // log messages such as the one below.
- // Lower level log messages are used sparingly to minimize noise in the code.
- logger.fine("Command word: " + commandWord + "; Arguments: " + 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:
- logger.finer("This user input caused a ParseException: " + userInput);
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
deleted file mode 100644
index bd1ca0f56c8..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ /dev/null
@@ -1,109 +0,0 @@
-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;
-
-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;
-
-/**
- * Jackson-friendly version of {@link Person}.
- */
-class JsonAdaptedPerson {
-
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
-
- private final String name;
- private final String phone;
- private final String email;
- private final String address;
- private final List tags = new ArrayList<>();
-
- /**
- * 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("tags") List tags) {
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- if (tags != null) {
- this.tags.addAll(tags);
- }
- }
-
- /**
- * Converts a given {@code Person} into this class for Jackson use.
- */
- public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
- phone = source.getPhone().value;
- email = source.getEmail().value;
- address = source.getAddress().value;
- tags.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
- }
-
- /**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
- */
- public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tags) {
- personTags.add(tag.toModelType());
- }
-
- if (name == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
- }
- if (!Name.isValidName(name)) {
- throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
- }
- final Name modelName = new Name(name);
-
- if (phone == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
- }
- if (!Phone.isValidPhone(phone)) {
- throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
- }
- final Phone modelPhone = new Phone(phone);
-
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.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);
- }
-
-}
diff --git a/src/main/resources/images/BizBook.png b/src/main/resources/images/BizBook.png
new file mode 100644
index 00000000000..5b1becb38a0
Binary files /dev/null and b/src/main/resources/images/BizBook.png differ
diff --git a/src/main/resources/view/CommandBox.fxml b/src/main/resources/view/CommandBox.fxml
index 124283a392e..ae9dde2fbf3 100644
--- a/src/main/resources/view/CommandBox.fxml
+++ b/src/main/resources/view/CommandBox.fxml
@@ -1,9 +1,29 @@
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/CommandTablePanel.fxml b/src/main/resources/view/CommandTablePanel.fxml
new file mode 100644
index 00000000000..660e7e735c5
--- /dev/null
+++ b/src/main/resources/view/CommandTablePanel.fxml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/ContactDetails.fxml b/src/main/resources/view/ContactDetails.fxml
new file mode 100644
index 00000000000..97fc58afb5b
--- /dev/null
+++ b/src/main/resources/view/ContactDetails.fxml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..454b31ba8bf 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -39,6 +39,11 @@
-fx-max-height: 0;
}
+/* Solution below adapted from https://stackoverflow.com/a/40003066/4428725 */
+.scroll-pane .viewport {
+ -fx-background-color: transparent;
+}
+
.table-view {
-fx-base: #1d1d1d;
-fx-control-inner-background: #1d1d1d;
@@ -57,10 +62,10 @@
-fx-border-width: 0 0 1 0;
-fx-background-color: transparent;
-fx-border-color:
- transparent
- transparent
- derive(-fx-base, 80%)
- transparent;
+ transparent
+ transparent
+ derive(-fx-base, 80%)
+ transparent;
-fx-border-insets: 0 10 1 0;
}
@@ -132,20 +137,36 @@
-fx-text-fill: #010504;
}
+.pane {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
.stack-pane {
- -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-background-color: derive(#1d1d1d, 20%);
}
.pane-with-border {
- -fx-background-color: derive(#1d1d1d, 20%);
- -fx-border-color: derive(#1d1d1d, 10%);
- -fx-border-top-width: 1px;
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-border-color: derive(#1d1d1d, 10%);
+ -fx-border-top-width: 1px;
+}
+.pane-with-person-info{
+ -fx-background-color: derive(#1d1d1d, 20%);
+ -fx-text-fill: white;
+ -fx-padding: 4px;
+ -fx-pref-height: 30px;
}
-
.status-bar {
-fx-background-color: derive(#1d1d1d, 30%);
}
+.search-bar {
+ -fx-background-color: derive(#1d1d1d, 50%);
+ -fx-border-color: derive(#1d1d1d, 50%);;
+ -fx-border-top-width: 2px;
+ -fx-text-fill: white;
+}
+
.result-display {
-fx-background-color: transparent;
-fx-font-family: "Segoe UI Light";
@@ -179,11 +200,19 @@
-fx-border-color: derive(#1d1d1d, 30%);
-fx-border-width: 1px;
}
-
.grid-pane .stack-pane {
-fx-background-color: derive(#1d1d1d, 30%);
}
+/* ScrollPane styling */
+.scroll-pane {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.scroll-pane > .viewport {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
.context-menu {
-fx-background-color: derive(#1d1d1d, 50%);
}
@@ -229,8 +258,8 @@
}
.button:pressed, .button:default:hover:pressed {
- -fx-background-color: white;
- -fx-text-fill: #1d1d1d;
+ -fx-background-color: white;
+ -fx-text-fill: #1d1d1d;
}
.button:focused {
@@ -343,10 +372,53 @@
}
#tags .label {
- -fx-text-fill: white;
- -fx-background-color: #3e7b91;
+ -fx-text-fill: black;
+ -fx-background-color: gold;
-fx-padding: 1 3 1 3;
- -fx-border-radius: 2;
- -fx-background-radius: 2;
+ -fx-border-radius: 5;
+ -fx-border-color: black;
+ -fx-background-radius: 5;
-fx-font-size: 11;
}
+/* Details Panel */
+#notes-label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+#notes-header {
+ -fx-font-size: 25pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: white;
+ -fx-opacity: 1;
+}
+
+
+.error {
+ -fx-text-fill: #d06651 !important; /* The error class should always override the default text-fill style */
+}
+
+.list-cell:empty {
+ /* Empty cells will not have alternating colours */
+ -fx-background: #383838;
+}
+
+.tag-selector {
+ -fx-border-width: 1;
+ -fx-border-color: white;
+ -fx-border-radius: 3;
+ -fx-background-radius: 3;
+}
+
+.tooltip-text {
+ -fx-text-fill: white;
+}
+
+.pinned-person-item {
+ -fx-background-color: #444;
+ -fx-background-radius: 1px;
+ -fx-max-width: 180;
+ -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);
+}
diff --git a/src/main/resources/view/Extensions.css b/src/main/resources/view/Extensions.css
index bfe82a85964..e69de29bb2d 100644
--- a/src/main/resources/view/Extensions.css
+++ b/src/main/resources/view/Extensions.css
@@ -1,20 +0,0 @@
-
-.error {
- -fx-text-fill: #d06651 !important; /* The error class should always override the default text-fill style */
-}
-
-.list-cell:empty {
- /* Empty cells will not have alternating colours */
- -fx-background: #383838;
-}
-
-.tag-selector {
- -fx-border-width: 1;
- -fx-border-color: white;
- -fx-border-radius: 3;
- -fx-background-radius: 3;
-}
-
-.tooltip-text {
- -fx-text-fill: white;
-}
diff --git a/src/main/resources/view/HelpWindow.css b/src/main/resources/view/HelpWindow.css
deleted file mode 100644
index 17e8a8722cd..00000000000
--- a/src/main/resources/view/HelpWindow.css
+++ /dev/null
@@ -1,19 +0,0 @@
-#copyButton, #helpMessage {
- -fx-text-fill: white;
-}
-
-#copyButton {
- -fx-background-color: dimgray;
-}
-
-#copyButton:hover {
- -fx-background-color: gray;
-}
-
-#copyButton:armed {
- -fx-background-color: darkgray;
-}
-
-#helpMessageContainer {
- -fx-background-color: derive(#1d1d1d, 20%);
-}
diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml
index e01f330de33..f900adfb1a1 100644
--- a/src/main/resources/view/HelpWindow.fxml
+++ b/src/main/resources/view/HelpWindow.fxml
@@ -6,39 +6,47 @@
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/HelpWindowDark.css b/src/main/resources/view/HelpWindowDark.css
new file mode 100644
index 00000000000..fe4a29f791d
--- /dev/null
+++ b/src/main/resources/view/HelpWindowDark.css
@@ -0,0 +1,50 @@
+#openButton,
+#helpMessage {
+ -fx-text-fill: white;
+}
+
+#openButton {
+ -fx-background-color: dimgray;
+}
+
+#openButton:hover {
+ -fx-background-color: gray;
+}
+
+#openButton:armed {
+ -fx-background-color: darkgray;
+}
+
+#helpMessageContainer {
+ -fx-background-color: derive(#1d1d1d, 20%);
+}
+
+.help-textbox {
+ -fx-text-fill: white;
+ -fx-fill: white;
+}
+
+#errorMessageLabel {
+ -fx-text-fill: red; /* Makes the text red */
+ -fx-padding: 0 0 0 10px; /* Adds 10px padding to the left */
+}
+
+.table-cell {
+ -fx-text-fill: white;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-wrap-text: true;
+}
+
+.table-row-cell:filled:even {
+ -fx-background-color: #3c3e3f;
+}
+
+.table-row-cell:filled:odd {
+ -fx-background-color: #515658;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: #424d5f;
+ -fx-border-color: #3e7b91;
+ -fx-border-width: 1;
+}
diff --git a/src/main/resources/view/HelpWindowLight.css b/src/main/resources/view/HelpWindowLight.css
new file mode 100644
index 00000000000..ff6f63afdd2
--- /dev/null
+++ b/src/main/resources/view/HelpWindowLight.css
@@ -0,0 +1,51 @@
+#openButton,
+#helpMessage {
+ -fx-text-fill: black;
+}
+
+#openButton {
+ -fx-background-color: lightgray;
+}
+
+#openButton:hover {
+ -fx-background-color: gainsboro;
+}
+
+#openButton:armed {
+ -fx-background-color: silver;
+}
+
+#helpMessageContainer {
+ -fx-background-color: derive(#f0f0f0, -20%);
+
+}
+
+#errorMessageLabel {
+ -fx-text-fill: red;
+ -fx-padding: 0 0 0 10px;
+}
+
+#help-textbox {
+ -fx-text-fill: black;
+
+}
+
+.table-cell {
+ -fx-text-fill: black;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-wrap-text: true;
+}
+
+.table-row-cell:filled:even {
+ -fx-background-color: #f9f9f9;
+}
+
+.table-row-cell:filled:odd {
+ -fx-background-color: #eaeaea;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: #cce7ff;
+ -fx-border-color: #88b9e0;
+ -fx-border-width: 1;
+}
diff --git a/src/main/resources/view/LightTheme.css b/src/main/resources/view/LightTheme.css
new file mode 100644
index 00000000000..000eb2b4595
--- /dev/null
+++ b/src/main/resources/view/LightTheme.css
@@ -0,0 +1,407 @@
+.background {
+ -fx-background-color: #f4f4f4;
+ background-color: #ffffff;
+}
+
+.label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #333333;
+ -fx-opacity: 0.9;
+}
+
+.label-bright {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #000000;
+ -fx-opacity: 1;
+}
+
+.label-header {
+ -fx-font-size: 32pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: #333333;
+ -fx-opacity: 1;
+}
+
+.text-field {
+ -fx-font-size: 12pt;
+ -fx-font-family: "Segoe UI Semibold";
+}
+
+.tab-pane {
+ -fx-padding: 0 0 0 1;
+}
+
+.tab-pane .tab-header-area {
+ -fx-padding: 0 0 0 0;
+ -fx-min-height: 0;
+ -fx-max-height: 0;
+}
+
+.table-view {
+ -fx-base: #ffffff;
+ -fx-control-inner-background: #ffffff;
+ -fx-background-color: #ffffff;
+ -fx-table-cell-border-color: #e0e0e0;
+ -fx-table-header-border-color: #e0e0e0;
+ -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+ -fx-background-color: #f0f0f0;
+}
+
+.table-view .column-header, .table-view .filler {
+ -fx-size: 35;
+ -fx-border-width: 0 0 1 0;
+ -fx-background-color: transparent;
+ -fx-border-color:
+ transparent
+ transparent
+ #c0c0c0
+ transparent;
+ -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+ -fx-font-size: 20pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: #333333;
+ -fx-alignment: center-left;
+ -fx-opacity: 1;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+ -fx-background-color: -fx-focus-color;
+}
+
+.split-pane:horizontal .split-pane-divider {
+ -fx-background-color: #e0e0e0;
+ -fx-border-color: transparent transparent transparent #c0c0c0;
+}
+
+.split-pane {
+ -fx-border-radius: 1;
+ -fx-border-width: 1;
+ -fx-background-color: #ffffff;
+}
+
+.list-view {
+ -fx-background-insets: 0;
+ -fx-padding: 0;
+ -fx-background-color: #ffffff;
+}
+
+.list-cell {
+ -fx-label-padding: 0 0 0 0;
+ -fx-graphic-text-gap : 0;
+ -fx-padding: 0 0 0 0;
+}
+
+.list-cell:filled:even {
+ -fx-background-color: #f8f8f8;
+}
+
+.list-cell:filled:odd {
+ -fx-background-color: #ffffff;
+}
+
+.list-cell:filled:selected {
+ -fx-background-color: #e0e0e0;
+}
+
+.list-cell:filled:selected #cardPane {
+ -fx-border-color: #3e7b91;
+ -fx-border-width: 1;
+}
+
+.list-cell .label {
+ -fx-text-fill: #333333;
+}
+
+.cell_big_label {
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-font-size: 16px;
+ -fx-text-fill: #010504;
+}
+
+.cell_small_label {
+ -fx-font-family: "Segoe UI";
+ -fx-font-size: 13px;
+ -fx-text-fill: #010504;
+}
+
+.pane {
+ -fx-background-color: #ffffff;
+}
+
+.stack-pane {
+ -fx-background-color: #ffffff;
+}
+
+.pane-with-border {
+ -fx-background-color: #ffffff;
+ -fx-border-color: #e0e0e0;
+ -fx-border-top-width: 1px;
+}
+
+.pane-with-person-info {
+ -fx-background-color: #ffffff;
+ -fx-text-fill: #333333;
+ -fx-padding: 4px;
+ -fx-pref-height: 30px;
+}
+
+
+.search-bar {
+ -fx-background-color: derive(#ffffff, 80%);
+ -fx-border-color: derive(#000000, 30%);
+ -fx-border-top-width: 2px;
+ -fx-text-fill: black;
+}
+
+.status-bar {
+ -fx-background-color: #f0f0f0;
+}
+
+.result-display {
+ -fx-background-color: transparent;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 13pt;
+ -fx-text-fill: #333333;
+}
+
+.result-display .label {
+ -fx-text-fill: #333333 !important;
+}
+
+.status-bar .label {
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: #333333;
+ -fx-padding: 4px;
+ -fx-pref-height: 30px;
+}
+
+.status-bar-with-border {
+ -fx-background-color: #f0f0f0;
+ -fx-border-color: #e0e0e0;
+ -fx-border-width: 1px;
+}
+
+.status-bar-with-border .label {
+ -fx-text-fill: #333333;
+}
+
+.grid-pane {
+ -fx-background-color: #ffffff;
+ -fx-border-color: #e0e0e0;
+ -fx-border-width: 1px;
+}
+
+.grid-pane .stack-pane {
+ -fx-background-color: #ffffff;
+}
+
+.context-menu {
+ -fx-background-color: #f0f0f0;
+}
+
+.context-menu .label {
+ -fx-text-fill: #333333;
+}
+
+.menu-bar {
+ -fx-background-color: #f0f0f0;
+}
+
+.menu-bar .label {
+ -fx-font-size: 14pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: #333333;
+ -fx-opacity: 0.9;
+}
+
+.menu .left-container {
+ -fx-background-color: #ffffff;
+}
+
+.button {
+ -fx-padding: 5 22 5 22;
+ -fx-border-color: #e2e2e2;
+ -fx-border-width: 2;
+ -fx-background-radius: 0;
+ -fx-background-color: #ffffff;
+ -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+ -fx-font-size: 11pt;
+ -fx-text-fill: #333333;
+ -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.button:hover {
+ -fx-background-color: #e0e0e0;
+}
+
+.button:pressed, .button:default:hover:pressed {
+ -fx-background-color: #333333;
+ -fx-text-fill: #ffffff;
+}
+
+.button:focused {
+ -fx-border-color: #333333, #333333;
+ -fx-border-width: 1, 1;
+ -fx-border-style: solid, segments(1, 1);
+ -fx-border-radius: 0, 0;
+ -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+ -fx-opacity: 0.4;
+ -fx-background-color: #ffffff;
+ -fx-text-fill: #333333;
+}
+
+.button:default {
+ -fx-background-color: -fx-focus-color;
+ -fx-text-fill: #ffffff;
+}
+
+.button:default:hover {
+ -fx-background-color: derive(-fx-focus-color, 30%);
+}
+
+.dialog-pane {
+ -fx-background-color: #ffffff;
+}
+
+.dialog-pane > *.button-bar > *.container {
+ -fx-background-color: #ffffff;
+}
+
+.dialog-pane > *.label.content {
+ -fx-font-size: 14px;
+ -fx-font-weight: bold;
+ -fx-text-fill: #333333;
+}
+
+.dialog-pane:header *.header-panel {
+ -fx-background-color: #f0f0f0;
+}
+
+.dialog-pane:header *.header-panel *.label {
+ -fx-font-size: 18px;
+ -fx-font-style: italic;
+ -fx-fill: #333333;
+ -fx-text-fill: #333333;
+}
+
+.scroll-bar {
+ -fx-background-color: #f0f0f0;
+}
+
+.scroll-bar .thumb {
+ -fx-background-color: #c0c0c0;
+ -fx-background-insets: 3;
+}
+
+.scroll-bar .increment-button, .scroll-bar .decrement-button {
+ -fx-background-color: transparent;
+ -fx-padding: 0 0 0 0;
+}
+
+.scroll-bar .increment-arrow, .scroll-bar .decrement-arrow {
+ -fx-shape: " ";
+}
+
+.scroll-bar:vertical .increment-arrow, .scroll-bar:vertical .decrement-arrow {
+ -fx-padding: 1 8 1 8;
+}
+
+.scroll-bar:horizontal .increment-arrow, .scroll-bar:horizontal .decrement-arrow {
+ -fx-padding: 8 1 8 1;
+}
+
+#cardPane {
+ -fx-background-color: transparent;
+ -fx-border-width: 0;
+}
+
+#commandTypeLabel {
+ -fx-font-size: 11px;
+ -fx-text-fill: #2196F3;
+}
+
+#commandTextField {
+ -fx-background-color: transparent #ffffff transparent #ffffff;
+ -fx-background-insets: 0;
+ -fx-border-color: #ffffff #ffffff #333333 #ffffff;
+ -fx-border-insets: 0;
+ -fx-border-width: 1;
+ -fx-font-family: "Segoe UI Light";
+ -fx-font-size: 13pt;
+ -fx-text-fill: #333333;
+}
+
+#filterField, #personListPanel, #personWebpage {
+ -fx-effect: innershadow(gaussian, #e0e0e0, 10, 0, 0, 0);
+}
+
+#resultDisplay .content {
+ -fx-background-color: transparent, #ffffff, transparent, #ffffff;
+ -fx-background-radius: 0;
+}
+
+#tags {
+ -fx-hgap: 7;
+ -fx-vgap: 3;
+}
+
+#tags .label {
+ -fx-text-fill: #ffffff;
+ -fx-background-color: #3e7b91;
+ -fx-padding: 1 3 1 3;
+ -fx-border-radius: 5;
+ -fx-border-color: #3e7b91;
+ -fx-background-radius: 5;
+ -fx-font-size: 11;
+}
+
+#notes-label {
+ -fx-font-size: 11pt;
+ -fx-font-family: "Segoe UI Semibold";
+ -fx-text-fill: #333333;
+ -fx-opacity: 1;
+}
+
+#notes-header {
+ -fx-font-size: 25pt;
+ -fx-font-family: "Segoe UI Light";
+ -fx-text-fill: #333333;
+ -fx-opacity: 1;
+}
+
+.pinned-person-item {
+ -fx-background-color: #f0f0f0;
+ -fx-background-radius: 1px;
+ -fx-max-width: 180;
+ -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.2), 10, 0, 0, 0);
+}
+
+.error {
+ -fx-text-fill: #d32f2f !important;
+}
+
+.list-cell:empty {
+ -fx-background: #ffffff;
+}
+
+.tag-selector {
+ -fx-border-width: 1;
+ -fx-border-color: #333333;
+ -fx-border-radius: 3;
+ -fx-background-radius: 3;
+}
+
+.tooltip-text {
+ -fx-text-fill: #333333;
+}
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..11b5f22335e 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -6,21 +6,20 @@
-
+
+ title="BizBook" minWidth="750" minHeight="600" onCloseRequest="#handleExit">
-
+
-
@@ -28,30 +27,47 @@
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
-
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml
index 84e09833a87..9bc35f6c655 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PersonListCard.fxml
@@ -25,12 +25,13 @@
-
+
+
+
+
+
-
-
-
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PersonListPanel.fxml
index a1bb6bbace8..152b5b4f2fa 100644
--- a/src/main/resources/view/PersonListPanel.fxml
+++ b/src/main/resources/view/PersonListPanel.fxml
@@ -1,8 +1,4 @@
-
-
-
-
-
+
diff --git a/src/main/resources/view/PinnedPersonCard.fxml b/src/main/resources/view/PinnedPersonCard.fxml
new file mode 100644
index 00000000000..9cc77be6bab
--- /dev/null
+++ b/src/main/resources/view/PinnedPersonCard.fxml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PinnedPersonListPanel.fxml b/src/main/resources/view/PinnedPersonListPanel.fxml
new file mode 100644
index 00000000000..0d1be935de9
--- /dev/null
+++ b/src/main/resources/view/PinnedPersonListPanel.fxml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/main/resources/view/SearchBox.fxml b/src/main/resources/view/SearchBox.fxml
new file mode 100644
index 00000000000..e8a752ca269
--- /dev/null
+++ b/src/main/resources/view/SearchBox.fxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePinnedPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/duplicatePinnedPersonAddressBook.json
new file mode 100644
index 00000000000..a116ec5f2ac
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/duplicatePinnedPersonAddressBook.json
@@ -0,0 +1,46 @@
+{
+ "persons": [
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Benson Meier",
+ "phone": "98765432",
+ "email": "johnd@example.com",
+ "address": "311, Clementi Ave 2, #02-25",
+ "tags": ["owesMoney", "friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Carl Kurz",
+ "phone": "95352563",
+ "email": "heinz@example.com",
+ "address": "wall street",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ],
+ "pinnedPersons": [
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPinnedPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPinnedPersonAddressBook.json
new file mode 100644
index 00000000000..eeaeb83cc2e
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/invalidPinnedPersonAddressBook.json
@@ -0,0 +1,38 @@
+{
+ "persons": [
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Benson Meier",
+ "phone": "98765432",
+ "email": "johnd@example.com",
+ "address": "311, Clementi Ave 2, #02-25",
+ "tags": ["owesMoney", "friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Carl Kurz",
+ "phone": "95352563",
+ "email": "heinz@example.com",
+ "address": "wall street",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ],
+ "pinnedPersons": [
+ {
+ "name": "Daniel Meier",
+ "phone": "87652533",
+ "email": "cornelia@example.com",
+ "address": "10th street",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
index 72262099d35..7964406515d 100644
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
@@ -1,46 +1,61 @@
{
"_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
- "persons" : [ {
- "name" : "Alice Pauline",
- "phone" : "94351253",
- "email" : "alice@example.com",
- "address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
- }, {
- "name" : "Benson Meier",
- "phone" : "98765432",
- "email" : "johnd@example.com",
- "address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
- }, {
- "name" : "Carl Kurz",
- "phone" : "95352563",
- "email" : "heinz@example.com",
- "address" : "wall street",
- "tags" : [ ]
- }, {
- "name" : "Daniel Meier",
- "phone" : "87652533",
- "email" : "cornelia@example.com",
- "address" : "10th street",
- "tags" : [ "friends" ]
- }, {
- "name" : "Elle Meyer",
- "phone" : "9482224",
- "email" : "werner@example.com",
- "address" : "michegan ave",
- "tags" : [ ]
- }, {
- "name" : "Fiona Kunz",
- "phone" : "9482427",
- "email" : "lydia@example.com",
- "address" : "little tokyo",
- "tags" : [ ]
- }, {
- "name" : "George Best",
- "phone" : "9482442",
- "email" : "anna@example.com",
- "address" : "4th street",
- "tags" : [ ]
- } ]
+ "persons": [
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Benson Meier",
+ "phone": "98765432",
+ "email": "johnd@example.com",
+ "address": "311, Clementi Ave 2, #02-25",
+ "tags": ["owesMoney", "friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Carl Kurz",
+ "phone": "95352563",
+ "email": "heinz@example.com",
+ "address": "wall street",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Daniel Meier",
+ "phone": "87652533",
+ "email": "cornelia@example.com",
+ "address": "10th street",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Elle Meyer",
+ "phone": "94822245",
+ "email": "werner@example.com",
+ "address": "michegan ave",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Fiona Kunz",
+ "phone": "94824275",
+ "email": "lydia@example.com",
+ "address": "little tokyo",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "George Best",
+ "phone": "94824423",
+ "email": "anna@example.com",
+ "address": "4th street",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ]
}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPinnedPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPinnedPersonsAddressBook.json
new file mode 100644
index 00000000000..eecffb2bada
--- /dev/null
+++ b/src/test/data/JsonSerializableAddressBookTest/typicalPinnedPersonsAddressBook.json
@@ -0,0 +1,71 @@
+{
+ "_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
+ "persons": [
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Benson Meier",
+ "phone": "98765432",
+ "email": "johnd@example.com",
+ "address": "311, Clementi Ave 2, #02-25",
+ "tags": ["owesMoney", "friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Carl Kurz",
+ "phone": "95352563",
+ "email": "heinz@example.com",
+ "address": "wall street",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Daniel Meier",
+ "phone": "87652533",
+ "email": "cornelia@example.com",
+ "address": "10th street",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Elle Meyer",
+ "phone": "94822245",
+ "email": "werner@example.com",
+ "address": "michegan ave",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "Fiona Kunz",
+ "phone": "94824275",
+ "email": "lydia@example.com",
+ "address": "little tokyo",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ },
+ {
+ "name": "George Best",
+ "phone": "94824423",
+ "email": "anna@example.com",
+ "address": "4th street",
+ "tags": [],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ],
+ "pinnedPersons": [
+ {
+ "name": "Alice Pauline",
+ "phone": "94351253",
+ "email": "alice@example.com",
+ "address": "123, Jurong West Ave 6, #08-111",
+ "tags": ["friends"],
+ "notes": ["High profile client", "Likes dumplings"]
+ }
+ ]
+}
diff --git a/src/test/java/seedu/address/AppParametersTest.java b/src/test/java/bizbook/AppParametersTest.java
similarity index 99%
rename from src/test/java/seedu/address/AppParametersTest.java
rename to src/test/java/bizbook/AppParametersTest.java
index 133cc008bce..dd93b9e78a5 100644
--- a/src/test/java/seedu/address/AppParametersTest.java
+++ b/src/test/java/bizbook/AppParametersTest.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package bizbook;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
diff --git a/src/test/java/seedu/address/commons/core/ConfigTest.java b/src/test/java/bizbook/commons/core/ConfigTest.java
similarity index 95%
rename from src/test/java/seedu/address/commons/core/ConfigTest.java
rename to src/test/java/bizbook/commons/core/ConfigTest.java
index d3ba2a52a89..a4afa6a12d7 100644
--- a/src/test/java/seedu/address/commons/core/ConfigTest.java
+++ b/src/test/java/bizbook/commons/core/ConfigTest.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
diff --git a/src/test/java/seedu/address/commons/core/GuiSettingsTest.java b/src/test/java/bizbook/commons/core/GuiSettingsTest.java
similarity index 93%
rename from src/test/java/seedu/address/commons/core/GuiSettingsTest.java
rename to src/test/java/bizbook/commons/core/GuiSettingsTest.java
index b7876c4349d..ecf2d930726 100644
--- a/src/test/java/seedu/address/commons/core/GuiSettingsTest.java
+++ b/src/test/java/bizbook/commons/core/GuiSettingsTest.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/src/test/java/seedu/address/commons/core/VersionTest.java b/src/test/java/bizbook/commons/core/VersionTest.java
similarity index 98%
rename from src/test/java/seedu/address/commons/core/VersionTest.java
rename to src/test/java/bizbook/commons/core/VersionTest.java
index 495cd231554..4469b650175 100644
--- a/src/test/java/seedu/address/commons/core/VersionTest.java
+++ b/src/test/java/bizbook/commons/core/VersionTest.java
@@ -1,8 +1,8 @@
-package seedu.address.commons.core;
+package bizbook.commons.core;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/commons/core/index/IndexTest.java b/src/test/java/bizbook/commons/core/index/IndexTest.java
similarity index 95%
rename from src/test/java/seedu/address/commons/core/index/IndexTest.java
rename to src/test/java/bizbook/commons/core/index/IndexTest.java
index fc395ab964b..379009effe6 100644
--- a/src/test/java/seedu/address/commons/core/index/IndexTest.java
+++ b/src/test/java/bizbook/commons/core/index/IndexTest.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.core.index;
+package bizbook.commons.core.index;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/commons/util/AppUtilTest.java b/src/test/java/bizbook/commons/util/AppUtilTest.java
similarity index 85%
rename from src/test/java/seedu/address/commons/util/AppUtilTest.java
rename to src/test/java/bizbook/commons/util/AppUtilTest.java
index 594de1e6365..36a1543b1d3 100644
--- a/src/test/java/seedu/address/commons/util/AppUtilTest.java
+++ b/src/test/java/bizbook/commons/util/AppUtilTest.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
@@ -9,7 +9,7 @@ public class AppUtilTest {
@Test
public void getImage_exitingImage() {
- assertNotNull(AppUtil.getImage("/images/address_book_32.png"));
+ assertNotNull(AppUtil.getImage("/images/BizBook.png"));
}
@Test
diff --git a/src/test/java/seedu/address/commons/util/CollectionUtilTest.java b/src/test/java/bizbook/commons/util/CollectionUtilTest.java
similarity index 96%
rename from src/test/java/seedu/address/commons/util/CollectionUtilTest.java
rename to src/test/java/bizbook/commons/util/CollectionUtilTest.java
index b467a3dc025..a31fddf6697 100644
--- a/src/test/java/seedu/address/commons/util/CollectionUtilTest.java
+++ b/src/test/java/bizbook/commons/util/CollectionUtilTest.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
+import static bizbook.commons.util.CollectionUtil.requireAllNonNull;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-import static seedu.address.testutil.Assert.assertThrows;
import java.util.Arrays;
import java.util.Collection;
diff --git a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java b/src/test/java/bizbook/commons/util/ConfigUtilTest.java
similarity index 94%
rename from src/test/java/seedu/address/commons/util/ConfigUtilTest.java
rename to src/test/java/bizbook/commons/util/ConfigUtilTest.java
index 69d7b89cfd8..20f98be466a 100644
--- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java
+++ b/src/test/java/bizbook/commons/util/ConfigUtilTest.java
@@ -1,8 +1,8 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static seedu.address.testutil.Assert.assertThrows;
import java.io.IOException;
import java.nio.file.Path;
@@ -13,8 +13,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.exceptions.DataLoadingException;
+import bizbook.commons.core.Config;
+import bizbook.commons.exceptions.DataLoadingException;
public class ConfigUtilTest {
diff --git a/src/test/java/seedu/address/commons/util/FileUtilTest.java b/src/test/java/bizbook/commons/util/FileUtilTest.java
similarity index 84%
rename from src/test/java/seedu/address/commons/util/FileUtilTest.java
rename to src/test/java/bizbook/commons/util/FileUtilTest.java
index 1fe5478c756..10c007b6dac 100644
--- a/src/test/java/seedu/address/commons/util/FileUtilTest.java
+++ b/src/test/java/bizbook/commons/util/FileUtilTest.java
@@ -1,8 +1,8 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/bizbook/commons/util/JsonUtilTest.java
similarity index 92%
rename from src/test/java/seedu/address/commons/util/JsonUtilTest.java
rename to src/test/java/bizbook/commons/util/JsonUtilTest.java
index d4907539dee..eb8cd479e59 100644
--- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java
+++ b/src/test/java/bizbook/commons/util/JsonUtilTest.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -7,8 +7,8 @@
import org.junit.jupiter.api.Test;
-import seedu.address.testutil.SerializableTestClass;
-import seedu.address.testutil.TestUtil;
+import bizbook.testutil.SerializableTestClass;
+import bizbook.testutil.TestUtil;
/**
* Tests JSON Read and Write
diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/bizbook/commons/util/StringUtilTest.java
similarity index 98%
rename from src/test/java/seedu/address/commons/util/StringUtilTest.java
rename to src/test/java/bizbook/commons/util/StringUtilTest.java
index c56d407bf3f..2e9275418b1 100644
--- a/src/test/java/seedu/address/commons/util/StringUtilTest.java
+++ b/src/test/java/bizbook/commons/util/StringUtilTest.java
@@ -1,8 +1,8 @@
-package seedu.address.commons.util;
+package bizbook.commons.util;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import java.io.FileNotFoundException;
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/bizbook/logic/LogicManagerTest.java
similarity index 84%
rename from src/test/java/seedu/address/logic/LogicManagerTest.java
rename to src/test/java/bizbook/logic/LogicManagerTest.java
index baf8ce336a2..c6073d442fc 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/bizbook/logic/LogicManagerTest.java
@@ -1,14 +1,14 @@
-package seedu.address.logic;
-
+package bizbook.logic;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static bizbook.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static bizbook.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.AMY;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
-import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.AMY;
import java.io.IOException;
import java.nio.file.AccessDeniedException;
@@ -18,20 +18,20 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.storage.JsonAddressBookStorage;
-import seedu.address.storage.JsonUserPrefsStorage;
-import seedu.address.storage.StorageManager;
-import seedu.address.testutil.PersonBuilder;
+import bizbook.logic.commands.AddCommand;
+import bizbook.logic.commands.CommandResult;
+import bizbook.logic.commands.ListCommand;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+import bizbook.storage.JsonAddressBookStorage;
+import bizbook.storage.JsonUserPrefsStorage;
+import bizbook.storage.StorageManager;
+import bizbook.testutil.PersonBuilder;
public class LogicManagerTest {
private static final IOException DUMMY_IO_EXCEPTION = new IOException("dummy IO exception");
@@ -92,6 +92,7 @@ public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException
* - no exceptions are thrown
* - the feedback message is equal to {@code expectedMessage}
* - the internal model manager state is the same as that in {@code expectedModel}
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandSuccess(String inputCommand, String expectedMessage,
@@ -103,6 +104,7 @@ private void assertCommandSuccess(String inputCommand, String expectedMessage,
/**
* Executes the command, confirms that a ParseException is thrown and that the result message is correct.
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertParseException(String inputCommand, String expectedMessage) {
@@ -111,6 +113,7 @@ private void assertParseException(String inputCommand, String expectedMessage) {
/**
* Executes the command, confirms that a CommandException is thrown and that the result message is correct.
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandException(String inputCommand, String expectedMessage) {
@@ -119,6 +122,7 @@ private void assertCommandException(String inputCommand, String expectedMessage)
/**
* Executes the command, confirms that the exception is thrown and that the result message is correct.
+ *
* @see #assertCommandFailure(String, Class, String, Model)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
@@ -132,6 +136,7 @@ private void assertCommandFailure(String inputCommand, Class extends Throwable
* - the {@code expectedException} is thrown
* - the resulting error message is equal to {@code expectedMessage}
* - the internal model manager state is the same as that in {@code expectedModel}
+ *
* @see #assertCommandSuccess(String, String, Model)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/bizbook/logic/commands/AddCommandIntegrationTest.java
similarity index 68%
rename from src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
rename to src/test/java/bizbook/logic/commands/AddCommandIntegrationTest.java
index 162a0c86031..09e8ed9511a 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/bizbook/logic/commands/AddCommandIntegrationTest.java
@@ -1,18 +1,18 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.PersonBuilder;
+import bizbook.logic.Messages;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+import bizbook.testutil.PersonBuilder;
/**
* Contains integration tests (interaction with the Model) for {@code AddCommand}.
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/bizbook/logic/commands/AddCommandTest.java
similarity index 72%
rename from src/test/java/seedu/address/logic/commands/AddCommandTest.java
rename to src/test/java/bizbook/logic/commands/AddCommandTest.java
index 90e8253f48e..99c8d108d57 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/AddCommandTest.java
@@ -1,11 +1,11 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.ALICE;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -14,16 +14,17 @@
import org.junit.jupiter.api.Test;
+import bizbook.commons.core.GuiSettings;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.ReadOnlyUserPrefs;
+import bizbook.model.person.Person;
+import bizbook.testutil.PersonBuilder;
+import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.logic.Messages;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.PersonBuilder;
public class AddCommandTest {
@@ -113,6 +114,11 @@ public Path getAddressBookFilePath() {
throw new AssertionError("This method should not be called.");
}
+ @Override
+ public ObjectProperty getFocusedPerson() {
+ throw new AssertionError("This method should not be called.");
+ }
+
@Override
public void setAddressBookFilePath(Path addressBookFilePath) {
throw new AssertionError("This method should not be called.");
@@ -157,6 +163,61 @@ public ObservableList getFilteredPersonList() {
public void updateFilteredPersonList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+
+ @Override
+ public ObservableList getPinnedPersonList() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean isPinned(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void pinPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean canUndo() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void unpinPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void saveAddressBookVersion() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void revertAddressBookVersion() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void setFocusPerson(Person person) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void updateFocusPerson(Person previousPerson, Person currentPerson) {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public boolean canRedo() {
+ throw new AssertionError("This method should not be called.");
+ }
+
+ @Override
+ public void redoAddressBookVersion() {
+ throw new AssertionError("This method should not be called.");
+ }
}
/**
diff --git a/src/test/java/bizbook/logic/commands/AddNoteCommandTest.java b/src/test/java/bizbook/logic/commands/AddNoteCommandTest.java
new file mode 100644
index 00000000000..53137df1836
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/AddNoteCommandTest.java
@@ -0,0 +1,145 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_ALICE;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_HIGH_PROFILE_CLIENT;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.PersonBuilder.DEFAULT_ADDRESS;
+import static bizbook.testutil.PersonBuilder.DEFAULT_EMAIL;
+import static bizbook.testutil.PersonBuilder.DEFAULT_NAME;
+import static bizbook.testutil.PersonBuilder.DEFAULT_PHONE;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalNotes.TYPICAL_NOTE;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.testutil.PersonBuilder;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+
+public class AddNoteCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void constructor_nullFields_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new AddNoteCommand(null, null));
+ }
+
+ @Test
+ public void execute_personAcceptedByModel_addSuccessful() throws Exception {
+
+ // Mock the model
+ Model modelMock = mock(Model.class);
+
+ // Create a valid person and set up the model's person list
+ Person validPerson = new PersonBuilder().withNotes().build();
+ ObservableList personList = FXCollections.observableArrayList(validPerson);
+
+ // Mock the behaviour of ModelMock to return personList when needed
+ when(modelMock.getFilteredPersonList()).thenReturn(personList);
+
+ // Create an ObjectProperty and mock getFocusedPerson to return it when needed
+ ObjectProperty focusedPersonProperty = new SimpleObjectProperty<>(validPerson);
+ when(modelMock.getFocusedPerson()).thenReturn(focusedPersonProperty);
+
+ // Set up the valid note and index for use in execution
+ Note validNote = new Note(VALID_NOTE_HIGH_PROFILE_CLIENT);
+ Index validIndex = INDEX_FIRST_PERSON;
+
+ AddNoteCommand addNoteCommand = new AddNoteCommand(validIndex, validNote);
+
+ // Execute the addNotesCommand
+ CommandResult commandResult = addNoteCommand.execute(modelMock);
+
+ String expected = "Added note to Person: " + DEFAULT_NAME + "; Phone: " + DEFAULT_PHONE + "; Email: "
+ + DEFAULT_EMAIL + "; Address: " + DEFAULT_ADDRESS + "; Tags: ; Notes: ["
+ + VALID_NOTE_HIGH_PROFILE_CLIENT + "]";
+
+ // Assert that the expected output is matched
+ assertEquals(expected, commandResult.getFeedbackToUser());
+
+ }
+
+ @Test
+ public void execute_duplicateNote_throwsCommandException() {
+ // Mock the model
+ Model modelMock = mock(Model.class);
+
+ // Create a valid person and set up the model's person list
+ Person validPerson = new PersonBuilder().withNotes(VALID_NOTE_HIGH_PROFILE_CLIENT).build();
+ ObservableList personList = FXCollections.observableArrayList(validPerson);
+
+ // Mock the behaviour of ModelMock to return personList when needed
+ when(modelMock.getFilteredPersonList()).thenReturn(personList);
+
+ // Create an ObjectProperty and mock getFocusedPerson to return it when needed
+ ObjectProperty focusedPersonProperty = new SimpleObjectProperty<>(validPerson);
+ when(modelMock.getFocusedPerson()).thenReturn(focusedPersonProperty);
+
+ // Set up the valid note and index for use in execution
+ Note validNote = new Note(VALID_NOTE_HIGH_PROFILE_CLIENT);
+ Index validIndex = INDEX_FIRST_PERSON;
+
+ AddNoteCommand addNoteCommand = new AddNoteCommand(validIndex, validNote);
+
+ // Assert that the expected error is thrown
+ assertThrows(CommandException.class, AddNoteCommand.DUPLICATE_MESSAGE_CONSTRAINTS, () ->
+ addNoteCommand.execute(modelMock));
+ }
+
+
+ @Test
+ public void execute_invalidPersonIndex_throwsCommandException() {
+ AddNoteCommand addNoteCommand = new AddNoteCommand(INDEX_OUTOFBOUND_PERSON,
+ TYPICAL_NOTE);
+ assertThrows(CommandException.class, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, () ->
+ addNoteCommand.execute(model));
+ }
+
+ @Test
+ public void equals() {
+ Note noteAlice = new Note(VALID_NOTE_ALICE);
+ Note noteBob = new Note(VALID_NOTE_BOB);
+ Index indexFirstPerson = INDEX_FIRST_PERSON;
+ Index indexSecondPerson = INDEX_SECOND_PERSON;
+
+ AddNoteCommand addAliceNoteCommand = new AddNoteCommand(indexFirstPerson, noteAlice);
+ AddNoteCommand addBobNoteCommand = new AddNoteCommand(indexSecondPerson, noteBob);
+
+ // same object -> returns true
+ assertTrue(addAliceNoteCommand.equals(addAliceNoteCommand));
+
+ // same values -> returns true
+ AddNoteCommand addAliceNoteCommandCopy = new AddNoteCommand(indexFirstPerson, noteAlice);
+ assertTrue(addAliceNoteCommand.equals(addAliceNoteCommandCopy));
+
+ // different types -> returns false
+ assertFalse(addAliceNoteCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(addAliceNoteCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(addAliceNoteCommand.equals(addBobNoteCommand));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/bizbook/logic/commands/ClearCommandTest.java
similarity index 68%
rename from src/test/java/seedu/address/logic/commands/ClearCommandTest.java
rename to src/test/java/bizbook/logic/commands/ClearCommandTest.java
index 80d9110c03a..822d523c765 100644
--- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/ClearCommandTest.java
@@ -1,14 +1,14 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
public class ClearCommandTest {
@@ -16,7 +16,6 @@ public class ClearCommandTest {
public void execute_emptyAddressBook_success() {
Model model = new ModelManager();
Model expectedModel = new ModelManager();
-
assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
}
diff --git a/src/test/java/seedu/address/logic/commands/CommandResultTest.java b/src/test/java/bizbook/logic/commands/CommandResultTest.java
similarity index 98%
rename from src/test/java/seedu/address/logic/commands/CommandResultTest.java
rename to src/test/java/bizbook/logic/commands/CommandResultTest.java
index 7b8c7cd4546..b3066d5234b 100644
--- a/src/test/java/seedu/address/logic/commands/CommandResultTest.java
+++ b/src/test/java/bizbook/logic/commands/CommandResultTest.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/bizbook/logic/commands/CommandTestUtil.java
similarity index 70%
rename from src/test/java/seedu/address/logic/commands/CommandTestUtil.java
rename to src/test/java/bizbook/logic/commands/CommandTestUtil.java
index 643a1d08069..4aad20b4063 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/bizbook/logic/commands/CommandTestUtil.java
@@ -1,25 +1,26 @@
-package seedu.address.logic.commands;
-
+package bizbook.logic.commands;
+
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-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.testutil.Assert.assertThrows;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.person.NameContainsKeywordsPredicate;
+import bizbook.model.person.Person;
+import bizbook.testutil.EditPersonDescriptorBuilder;
/**
* Contains helper methods for testing commands.
@@ -28,25 +29,40 @@ public class CommandTestUtil {
public static final String VALID_NAME_AMY = "Amy Bee";
public static final String VALID_NAME_BOB = "Bob Choo";
- public static final String VALID_PHONE_AMY = "11111111";
- public static final String VALID_PHONE_BOB = "22222222";
+ public static final String VALID_NAME_CHARLIE = "Charlie Dee";
+ public static final String VALID_PHONE_AMY = "91111111";
+ public static final String VALID_PHONE_BOB = "62222222";
+ public static final String VALID_PHONE_CHARLIE = "81111111";
public static final String VALID_EMAIL_AMY = "amy@example.com";
public static final String VALID_EMAIL_BOB = "bob@example.com";
+ public static final String VALID_EMAIL_CHARLIE = "charlie@example.com";
public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
+ public static final String VALID_ADDRESS_CHARLIE = "Block 987, Charlie Street 2";
public static final String VALID_TAG_HUSBAND = "husband";
public static final String VALID_TAG_FRIEND = "friend";
+ public static final String VALID_TAG_FRIENDS = "friends";
+ public static final String VALID_NOTE_LIKES_CATS = "likes cats";
+ public static final String VALID_NOTE_ALICE = "Alice note";
+ public static final String VALID_NOTE_BOB = "Bob note";
+ public static final String VALID_NOTE_HIGH_PROFILE_CLIENT = "High profile client";
+ public static final String VALID_NOTE_HIGH_PROFILE_CLIENT_LOWERCASE = "high profile client";
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
+ public static final String NAME_DESC_CHARLIE = " " + PREFIX_NAME + VALID_NAME_CHARLIE;
public static final String PHONE_DESC_AMY = " " + PREFIX_PHONE + VALID_PHONE_AMY;
public static final String PHONE_DESC_BOB = " " + PREFIX_PHONE + VALID_PHONE_BOB;
+ public static final String PHONE_DESC_CHARLIE = " " + PREFIX_PHONE + VALID_PHONE_CHARLIE;
public static final String EMAIL_DESC_AMY = " " + PREFIX_EMAIL + VALID_EMAIL_AMY;
public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB;
+ public static final String EMAIL_DESC_CHARLIE = " " + PREFIX_PHONE + VALID_EMAIL_CHARLIE;
public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY;
public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
+ public static final String ADDRESS_DESC_CHARLIE = " " + PREFIX_PHONE + VALID_ADDRESS_CHARLIE;
public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String NOTE_LIKES_CATS = " " + PREFIX_NOTES + VALID_NOTE_LIKES_CATS;
public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
@@ -59,6 +75,7 @@ public class CommandTestUtil {
public static final EditCommand.EditPersonDescriptor DESC_AMY;
public static final EditCommand.EditPersonDescriptor DESC_BOB;
+ public static final EditCommand.EditPersonDescriptor DESC_CHARLIE;
static {
DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
@@ -67,6 +84,9 @@ public class CommandTestUtil {
DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
.withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
.withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ DESC_CHARLIE = new EditPersonDescriptorBuilder().withName(VALID_NAME_CHARLIE)
+ .withPhone(VALID_PHONE_CHARLIE).withEmail(VALID_EMAIL_CHARLIE).withAddress(VALID_ADDRESS_CHARLIE)
+ .withTags(VALID_TAG_FRIEND).withNotes(VALID_NOTE_LIKES_CATS).build();
}
/**
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/bizbook/logic/commands/DeleteCommandTest.java
similarity index 75%
rename from src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
rename to src/test/java/bizbook/logic/commands/DeleteCommandTest.java
index b6f332eabca..e3d26850f7d 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/DeleteCommandTest.java
@@ -1,23 +1,24 @@
-package seedu.address.logic.commands;
-
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBookWithPinned;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
/**
* Contains integration tests (interaction with the Model) and unit tests for
@@ -25,7 +26,7 @@
*/
public class DeleteCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalAddressBookWithPinned(), new UserPrefs());
@Test
public void execute_validIndexUnfilteredList_success() {
@@ -33,7 +34,7 @@ public void execute_validIndexUnfilteredList_success() {
DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
- Messages.format(personToDelete));
+ Messages.formatShort(personToDelete));
ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.deletePerson(personToDelete);
@@ -57,7 +58,7 @@ public void execute_validIndexFilteredList_success() {
DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
- Messages.format(personToDelete));
+ Messages.formatShort(personToDelete));
Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
expectedModel.deletePerson(personToDelete);
@@ -66,6 +67,17 @@ public void execute_validIndexFilteredList_success() {
assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
}
+ @Test
+ public void execute_outOfBoundFilteredList_throwsCommandException() {
+ showPersonAtIndex(model, INDEX_FIRST_PERSON);
+
+ Index outOfBoundIndex = INDEX_OUTOFBOUND_PERSON;
+
+ DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+
+ assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
@Test
public void execute_invalidIndexFilteredList_throwsCommandException() {
showPersonAtIndex(model, INDEX_FIRST_PERSON);
diff --git a/src/test/java/bizbook/logic/commands/DeleteNoteCommandTest.java b/src/test/java/bizbook/logic/commands/DeleteNoteCommandTest.java
new file mode 100644
index 00000000000..6961e6c1f90
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/DeleteNoteCommandTest.java
@@ -0,0 +1,153 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_HIGH_PROFILE_CLIENT;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.PersonBuilder.DEFAULT_ADDRESS;
+import static bizbook.testutil.PersonBuilder.DEFAULT_EMAIL;
+import static bizbook.testutil.PersonBuilder.DEFAULT_NAME;
+import static bizbook.testutil.PersonBuilder.DEFAULT_PHONE;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_NOTE;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_NOTE;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
+import bizbook.testutil.PersonBuilder;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+
+public class DeleteNoteCommandTest {
+
+ @Test
+ public void constructor_nullFields_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new DeleteNoteCommand(null, null));
+ }
+
+ @Test
+ public void execute_validNoteDeletion_deletionSuccessful() throws Exception {
+
+ // Mock the model
+ Model modelMock = mock(Model.class);
+
+ // Create a valid person with a note and set up the model's person list
+ Person validPerson = new PersonBuilder().withNotes(VALID_NOTE_HIGH_PROFILE_CLIENT).build();
+ ObservableList personList = FXCollections.observableArrayList(validPerson);
+
+ // Mock the behavior of modelMock to return personList when needed
+ when(modelMock.getFilteredPersonList()).thenReturn(personList);
+
+ // Mock focused person property
+ ObjectProperty focusedPersonProperty = new SimpleObjectProperty<>(validPerson);
+ when(modelMock.getFocusedPerson()).thenReturn(focusedPersonProperty);
+
+ // Set up the person index and note index
+ Index validPersonIndex = INDEX_FIRST_PERSON;
+ Index validNoteIndex = INDEX_FIRST_PERSON;
+
+ DeleteNoteCommand deleteNoteCommand = new DeleteNoteCommand(validPersonIndex, validNoteIndex);
+
+ // Execute the deleteNotesCommand
+ CommandResult commandResult = deleteNoteCommand.execute(modelMock);
+
+ String expected = "Deleted note of Person: " + DEFAULT_NAME + "; Phone: " + DEFAULT_PHONE + "; Email: "
+ + DEFAULT_EMAIL + "; Address: " + DEFAULT_ADDRESS + "; Tags: ; Notes: ";
+
+ // Assert that the expected output is matched
+ assertEquals(expected, commandResult.getFeedbackToUser());
+ }
+
+ @Test
+ public void execute_invalidPersonIndex_throwsCommandException() {
+ // Mock the model
+ Model modelMock = mock(Model.class);
+
+ // Create a valid person with a note and set up the model's person list
+ Person validPerson = new PersonBuilder().withNotes(VALID_NOTE_HIGH_PROFILE_CLIENT).build();
+ ObservableList personList = FXCollections.observableArrayList(validPerson);
+
+ // Mock the behavior of modelMock to return personList when needed
+ when(modelMock.getFilteredPersonList()).thenReturn(personList);
+
+ // Mock focused person property
+ ObjectProperty focusedPersonProperty = new SimpleObjectProperty<>(validPerson);
+ when(modelMock.getFocusedPerson()).thenReturn(focusedPersonProperty);
+
+ // Set up a invalid person index and valid note index
+ Index invalidPersonIndex = INDEX_OUTOFBOUND_PERSON;
+ Index validNoteIndex = INDEX_FIRST_NOTE;
+
+ DeleteNoteCommand deleteNoteCommand = new DeleteNoteCommand(invalidPersonIndex, validNoteIndex);
+
+ // Assert that the expected error is thrown
+ assertThrows(CommandException.class, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, () ->
+ deleteNoteCommand.execute(modelMock));
+ }
+
+ @Test
+ public void execute_invalidNoteIndex_throwsCommandException() {
+ // Mock the model
+ Model modelMock = mock(Model.class);
+
+ // Create a valid person with a note and set up the model's person list
+ Person validPerson = new PersonBuilder().withNotes(VALID_NOTE_HIGH_PROFILE_CLIENT).build();
+ ObservableList personList = FXCollections.observableArrayList(validPerson);
+
+ // Mock the behavior of modelMock to return personList when needed
+ when(modelMock.getFilteredPersonList()).thenReturn(personList);
+
+ // Mock focused person property
+ ObjectProperty focusedPersonProperty = new SimpleObjectProperty<>(validPerson);
+ when(modelMock.getFocusedPerson()).thenReturn(focusedPersonProperty);
+
+ // Set up a valid person index and invalid note index
+ Index validPersonIndex = INDEX_FIRST_PERSON;
+ Index invalidNoteIndex = INDEX_OUTOFBOUND_NOTE;
+
+ DeleteNoteCommand deleteNoteCommand = new DeleteNoteCommand(validPersonIndex, invalidNoteIndex);
+
+ // Assert that the expected error is thrown
+ assertThrows(CommandException.class, Messages.MESSAGE_INVALID_NOTE_INDEX, ()
+ -> deleteNoteCommand.execute(modelMock));
+ }
+
+ @Test
+ public void equals() {
+ Index indexFirstPerson = INDEX_FIRST_PERSON;
+ Index indexSecondPerson = INDEX_SECOND_PERSON;
+ Index noteIndexFirst = INDEX_FIRST_PERSON;
+ Index noteIndexSecond = INDEX_SECOND_PERSON;
+
+ DeleteNoteCommand deleteFirstNoteCommand = new DeleteNoteCommand(indexFirstPerson, noteIndexFirst);
+ DeleteNoteCommand deleteSecondNoteCommand = new DeleteNoteCommand(indexSecondPerson, noteIndexSecond);
+
+ // same object -> returns true
+ assertTrue(deleteFirstNoteCommand.equals(deleteFirstNoteCommand));
+
+ // same values -> returns true
+ DeleteNoteCommand deleteFirstNoteCommandCopy = new DeleteNoteCommand(indexFirstPerson, noteIndexFirst);
+ assertTrue(deleteFirstNoteCommand.equals(deleteFirstNoteCommandCopy));
+
+ // different types -> returns false
+ assertFalse(deleteFirstNoteCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(deleteFirstNoteCommand.equals(null));
+
+ // different person or note -> returns false
+ assertFalse(deleteFirstNoteCommand.equals(deleteSecondNoteCommand));
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/DeleteTagCommandTest.java b/src/test/java/bizbook/logic/commands/DeleteTagCommandTest.java
new file mode 100644
index 00000000000..5e9fc4c2c4e
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/DeleteTagCommandTest.java
@@ -0,0 +1,92 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_FRIENDS;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+import bizbook.model.tag.Tag;
+import bizbook.testutil.PersonBuilder;
+
+public class DeleteTagCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_deleteTagCommand_success() throws Exception {
+ // Create the person and expected models as in the original
+ Person personToEdit = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+
+ // Define the edited person with updated tag
+ Person editedPerson = new PersonBuilder(personToEdit).withTags().build();
+
+ // Define the DeleteTagCommand
+ DeleteTagCommand deleteTagCommand = new DeleteTagCommand(INDEX_FIRST_PERSON, new Tag(VALID_TAG_FRIENDS));
+
+ // Define the expected message
+ String expectedMessage = String.format(DeleteTagCommand.MESSAGE_REMOVE_TAG_SUCCESS,
+ Messages.format(editedPerson));
+
+ // Create the expected model
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ expectedModel.setPerson(personToEdit, editedPerson);
+
+ assertCommandSuccess(deleteTagCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_invalidPersonIndex_throwsCommandException() {
+ DeleteTagCommand deleteTagCommand = new DeleteTagCommand(INDEX_OUTOFBOUND_PERSON, new Tag(VALID_TAG_FRIENDS));
+ assertThrows(CommandException.class,
+ MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, () -> deleteTagCommand.execute(model));
+ }
+
+ @Test
+ public void execute_nonExistentTag_throwsCommandException() {
+ DeleteTagCommand deleteTagCommand = new DeleteTagCommand(INDEX_FIRST_PERSON, new Tag(VALID_TAG_HUSBAND));
+ String expectedMessage = String.format(DeleteTagCommand.TAG_DOES_NOT_EXIST, VALID_TAG_HUSBAND);
+ assertThrows(CommandException.class,
+ expectedMessage, () -> deleteTagCommand.execute(model));
+ }
+
+ @Test
+ public void equals() {
+ DeleteTagCommand deleteTagFirstCommand = new DeleteTagCommand(INDEX_FIRST_PERSON,
+ new Tag(VALID_TAG_HUSBAND));
+ DeleteTagCommand deleteTagSecondCommand = new DeleteTagCommand(INDEX_SECOND_PERSON,
+ new Tag(VALID_TAG_FRIENDS));
+
+ // same object -> returns true
+ assertTrue(deleteTagFirstCommand.equals(deleteTagFirstCommand));
+
+ // same values -> returns true
+ DeleteTagCommand deleteTagFirstCommandCopy = new DeleteTagCommand(INDEX_FIRST_PERSON,
+ new Tag(VALID_TAG_HUSBAND));
+
+ assertTrue(deleteTagFirstCommand.equals(deleteTagFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(deleteTagFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(deleteTagFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(deleteTagFirstCommand.equals(deleteTagSecondCommand));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/bizbook/logic/commands/EditCommandTest.java
similarity index 84%
rename from src/test/java/seedu/address/logic/commands/EditCommandTest.java
rename to src/test/java/bizbook/logic/commands/EditCommandTest.java
index 469dd97daa7..627b7c92e54 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/EditCommandTest.java
@@ -1,39 +1,39 @@
-package seedu.address.logic.commands;
-
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBookWithPinned;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.Messages;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+import bizbook.testutil.EditPersonDescriptorBuilder;
+import bizbook.testutil.PersonBuilder;
/**
* Contains integration tests (interaction with the Model) and unit tests for EditCommand.
*/
public class EditCommandTest {
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model model = new ModelManager(getTypicalAddressBookWithPinned(), new UserPrefs());
@Test
public void execute_allFieldsSpecifiedUnfilteredList_success() {
diff --git a/src/test/java/bizbook/logic/commands/EditNoteCommandTest.java b/src/test/java/bizbook/logic/commands/EditNoteCommandTest.java
new file mode 100644
index 00000000000..e20d0b9be0c
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/EditNoteCommandTest.java
@@ -0,0 +1,82 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_NOTE_INDEX;
+import static bizbook.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.EditNoteCommand.DUPLICATE_MESSAGE_CONSTRAINTS;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_NOTE;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_NOTE;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalNotes.DUPLICATE_NOTE;
+import static bizbook.testutil.TypicalNotes.TYPICAL_NOTE;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+import bizbook.testutil.PersonBuilder;
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for
+ * EditCommand.
+ */
+public class EditNoteCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_editNotesCommand_success() throws Exception {
+ // Create the person and expected models as in the original
+ Person personToEdit = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+
+ // Define the edited person with updated notes
+ Person editedPerson = new PersonBuilder(personToEdit).withNotes(
+ TYPICAL_NOTE.getNote(), "Likes dumplings").build();
+
+ // Define the EditNotesCommand
+ EditNoteCommand editNoteCommand = new EditNoteCommand(INDEX_FIRST_PERSON, INDEX_FIRST_NOTE, TYPICAL_NOTE);
+
+ // Define the expected message
+ String expectedMessage = String.format(EditNoteCommand.MESSAGE_EDIT_NOTE_SUCCESS,
+ Messages.format(editedPerson));
+
+ // Create the expected model
+ Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ expectedModel.setPerson(personToEdit, editedPerson);
+ expectedModel.getFocusedPerson().set(editedPerson);
+ model.setPerson(personToEdit, personToEdit);
+
+ assertCommandSuccess(editNoteCommand, model, expectedMessage, expectedModel);
+ }
+
+
+ @Test
+ public void execute_duplicateNote_throwsCommandException() {
+ EditNoteCommand editNoteCommand = new EditNoteCommand(INDEX_SECOND_PERSON, INDEX_FIRST_NOTE, DUPLICATE_NOTE);
+ assertThrows(CommandException.class, DUPLICATE_MESSAGE_CONSTRAINTS, () -> editNoteCommand.execute(model));
+ }
+
+ @Test
+ public void execute_invalidPersonIndex_throwsCommandException() {
+ EditNoteCommand editNoteCommand = new EditNoteCommand(INDEX_OUTOFBOUND_PERSON, INDEX_FIRST_NOTE,
+ TYPICAL_NOTE);
+ assertThrows(CommandException.class, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX, () ->
+ editNoteCommand.execute(model));
+ }
+
+ @Test
+ public void execute_invalidNoteIndex_throwsCommandException() {
+ EditNoteCommand editNoteCommand = new EditNoteCommand(INDEX_SECOND_PERSON, INDEX_OUTOFBOUND_NOTE,
+ TYPICAL_NOTE);
+ assertThrows(CommandException.class, MESSAGE_INVALID_NOTE_INDEX, () -> editNoteCommand.execute(model));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/bizbook/logic/commands/EditPersonDescriptorTest.java
similarity index 78%
rename from src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
rename to src/test/java/bizbook/logic/commands/EditPersonDescriptorTest.java
index b17c1f3d5c2..026e23de317 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/bizbook/logic/commands/EditPersonDescriptorTest.java
@@ -1,20 +1,20 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
+import static bizbook.logic.commands.CommandTestUtil.DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.testutil.EditPersonDescriptorBuilder;
public class EditPersonDescriptorTest {
diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/bizbook/logic/commands/ExitCommandTest.java
similarity index 60%
rename from src/test/java/seedu/address/logic/commands/ExitCommandTest.java
rename to src/test/java/bizbook/logic/commands/ExitCommandTest.java
index 9533c473875..4d6abfbc349 100644
--- a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/ExitCommandTest.java
@@ -1,12 +1,12 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT;
import org.junit.jupiter.api.Test;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
public class ExitCommandTest {
private Model model = new ModelManager();
diff --git a/src/test/java/bizbook/logic/commands/ExportCommandTest.java b/src/test/java/bizbook/logic/commands/ExportCommandTest.java
new file mode 100644
index 00000000000..1e4f28b6239
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/ExportCommandTest.java
@@ -0,0 +1,73 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.ExportCommand.MESSAGE_SUCCESS;
+import static bizbook.logic.commands.exporter.Exporter.MESSAGE_EMPTY_ADDRESS_BOOK;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_CSV;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_VCF;
+import static bizbook.testutil.TypicalPersons.AMY;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+
+public class ExportCommandTest {
+ private Model model = new ModelManager();
+ private Model expectedModel = new ModelManager();
+
+ @Test
+ public void execute_export_success() {
+ model.addPerson(AMY);
+ expectedModel.addPerson(AMY);
+
+ CommandResult expectedCommandResult = new CommandResult(String.format(MESSAGE_SUCCESS, FILE_TYPE_CSV),
+ false, false);
+ assertCommandSuccess(new ExportCommand(FILE_TYPE_CSV), model, expectedCommandResult, expectedModel);
+ }
+
+ @Test
+ public void execute_emptyAddressBook_throwsCommandException() {
+ model.getFilteredPersonList().clear();
+ expectedModel.getFilteredPersonList().clear();
+
+ assertCommandFailure(new ExportCommand(FILE_TYPE_CSV), model, MESSAGE_EMPTY_ADDRESS_BOOK);
+ }
+
+ @Test
+ public void equals() {
+ ExportCommand exportFirstCommand = new ExportCommand(FILE_TYPE_CSV);
+ ExportCommand exportSecondCommand = new ExportCommand(FILE_TYPE_VCF);
+
+ // same object -> returns true
+ assertTrue(exportFirstCommand.equals(exportFirstCommand));
+
+ // same values -> returns true
+ ExportCommand exportFirstCommandCopy = new ExportCommand(FILE_TYPE_CSV);
+ assertTrue(exportFirstCommand.equals(exportFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(exportFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(exportFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(exportFirstCommand.equals(exportSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ ExportCommand firstExportCommand = new ExportCommand(FILE_TYPE_CSV);
+ String firstExportExpected = ExportCommand.class.getCanonicalName() + "{fileType=" + FILE_TYPE_CSV + "}";
+ assertEquals(firstExportExpected, firstExportCommand.toString());
+
+ ExportCommand secondExportCommand = new ExportCommand(FILE_TYPE_VCF);
+ String secondExportExpected = ExportCommand.class.getCanonicalName() + "{fileType=" + FILE_TYPE_VCF + "}";
+ assertEquals(secondExportExpected, secondExportCommand.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/bizbook/logic/commands/FindCommandTest.java
similarity index 75%
rename from src/test/java/seedu/address/logic/commands/FindCommandTest.java
rename to src/test/java/bizbook/logic/commands/FindCommandTest.java
index b8b7dbba91a..db171e54043 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/FindCommandTest.java
@@ -1,24 +1,24 @@
-package seedu.address.logic.commands;
-
+package bizbook.logic.commands;
+
+import static bizbook.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.TypicalPersons.CARL;
+import static bizbook.testutil.TypicalPersons.ELLE;
+import static bizbook.testutil.TypicalPersons.FIONA;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.CARL;
-import static seedu.address.testutil.TypicalPersons.ELLE;
-import static seedu.address.testutil.TypicalPersons.FIONA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import java.util.Arrays;
import java.util.Collections;
import org.junit.jupiter.api.Test;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.NameContainsKeywordsPredicate;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
@@ -74,6 +74,16 @@ public void execute_multipleKeywords_multiplePersonsFound() {
assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
}
+ @Test
+ public void execute_partialKeywords_multiplePersonsFound() {
+ String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 2);
+ NameContainsKeywordsPredicate predicate = preparePredicate("Ku");
+ FindCommand command = new FindCommand(predicate);
+ expectedModel.updateFilteredPersonList(predicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(CARL, FIONA), model.getFilteredPersonList());
+ }
+
@Test
public void toStringMethod() {
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
diff --git a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java b/src/test/java/bizbook/logic/commands/HelpCommandTest.java
similarity index 61%
rename from src/test/java/seedu/address/logic/commands/HelpCommandTest.java
rename to src/test/java/bizbook/logic/commands/HelpCommandTest.java
index 4904fc4352e..d4fced2ab9e 100644
--- a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/HelpCommandTest.java
@@ -1,12 +1,12 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE;
import org.junit.jupiter.api.Test;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
public class HelpCommandTest {
private Model model = new ModelManager();
diff --git a/src/test/java/bizbook/logic/commands/ImportCommandTest.java b/src/test/java/bizbook/logic/commands/ImportCommandTest.java
new file mode 100644
index 00000000000..a9001f678d9
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/ImportCommandTest.java
@@ -0,0 +1,112 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.ImportCommand.MESSAGE_FAILED_TO_LOAD;
+import static bizbook.logic.commands.ImportCommand.MESSAGE_SUCCESS;
+import static bizbook.logic.commands.exporter.VcfImporter.MESSAGE_INVALID_INFORMATION;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_CSV;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_VCF;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.model.AddressBook;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.testutil.TestUtil;
+
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code ImportCommand}.
+ */
+public class ImportCommandTest {
+ private static final String TYPICAL_VCF_FILE_PATH = "ImportCommandTest/typical.vcf";
+ private static final String MISSING_VCF_FILE_PATH = "ImportCommandTest/missing.vcf";
+ private static final String INVALID_INFO_VCF_FILE_PATH = "ImportCommandTest/invalid_info.vcf";
+
+ private Model model = new ModelManager();
+ private Model expectedModel = new ModelManager();
+
+ private Path convertToRelative(Path absolutePath) {
+ Path currentPath = Paths.get(".").toAbsolutePath();
+ return currentPath.relativize(absolutePath);
+ }
+
+ @Test
+ public void execute_importAbsolutePath_success() {
+ Path path = TestUtil.getResourceFilePath(ImportCommandTest.class, TYPICAL_VCF_FILE_PATH);
+
+ AddressBook addressBook = getTypicalAddressBook();
+ expectedModel.setAddressBook(addressBook);
+ CommandResult expectedCommandResult = new CommandResult(
+ String.format(MESSAGE_SUCCESS, addressBook.getPersonList().size()), false, false);
+
+ assertCommandSuccess(new ImportCommand(FILE_TYPE_VCF, path), model, expectedCommandResult, expectedModel);
+ }
+
+ @Test
+ public void execute_importRelativePath_success() {
+ Path path = convertToRelative(
+ TestUtil.getResourceFilePath(ImportCommandTest.class, TYPICAL_VCF_FILE_PATH));
+
+ AddressBook addressBook = getTypicalAddressBook();
+ expectedModel.setAddressBook(addressBook);
+ CommandResult expectedCommandResult = new CommandResult(
+ String.format(MESSAGE_SUCCESS, addressBook.getPersonList().size()), false, false);
+
+ assertCommandSuccess(new ImportCommand(FILE_TYPE_VCF, path), model, expectedCommandResult, expectedModel);
+ }
+
+ @Test
+ public void execute_importMissingFile_throwsCommandException() {
+ Path path = Path.of(MISSING_VCF_FILE_PATH);
+ assertCommandFailure(new ImportCommand(FILE_TYPE_VCF, path), model, MESSAGE_FAILED_TO_LOAD);
+ }
+
+ @Test
+ public void execute_importInvalidFile_throwsCommandException() {
+ Path path = TestUtil.getResourceFilePath(ImportCommandTest.class, INVALID_INFO_VCF_FILE_PATH);
+ assertCommandFailure(new ImportCommand(FILE_TYPE_VCF, path), model, MESSAGE_INVALID_INFORMATION);
+ }
+
+ @Test
+ public void equals() {
+ ImportCommand importFirstCommand = new ImportCommand(FILE_TYPE_CSV, Path.of("a"));
+
+ // same object -> returns true
+ assertTrue(importFirstCommand.equals(importFirstCommand));
+
+ // same values -> returns true
+ ImportCommand importFirstCommandCopy = new ImportCommand(FILE_TYPE_CSV, Path.of("a"));
+ assertTrue(importFirstCommand.equals(importFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(importFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(importFirstCommand.equals(null));
+
+ // different file type -> returns false
+ assertFalse(importFirstCommand.equals(new ImportCommand(FILE_TYPE_VCF, Path.of("a"))));
+
+ // different paths -> returns false
+ assertFalse(importFirstCommand.equals(new ImportCommand(FILE_TYPE_CSV, Path.of("b"))));
+ }
+
+ @Test
+ public void toStringMethod() {
+ Path path = Path.of("x", "y");
+ ImportCommand importCommand = new ImportCommand(FILE_TYPE_VCF, Path.of("x", "y"));
+ String secondImportExpected = ImportCommand.class.getCanonicalName()
+ + "{fileType=" + FILE_TYPE_VCF
+ + ", path=" + path + "}";
+ assertEquals(secondImportExpected, importCommand.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/bizbook/logic/commands/ListCommandTest.java
similarity index 65%
rename from src/test/java/seedu/address/logic/commands/ListCommandTest.java
rename to src/test/java/bizbook/logic/commands/ListCommandTest.java
index 435ff1f7275..4accab2c587 100644
--- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java
+++ b/src/test/java/bizbook/logic/commands/ListCommandTest.java
@@ -1,16 +1,16 @@
-package seedu.address.logic.commands;
+package bizbook.logic.commands;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
/**
* Contains integration tests (interaction with the Model) and unit tests for ListCommand.
diff --git a/src/test/java/bizbook/logic/commands/PinCommandTest.java b/src/test/java/bizbook/logic/commands/PinCommandTest.java
new file mode 100644
index 00000000000..8e0c75f2ac9
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/PinCommandTest.java
@@ -0,0 +1,86 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+
+public class PinCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_validIndexUnfilteredList_success() {
+ Person personToPin = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ PinCommand pinCommand = new PinCommand(INDEX_FIRST_PERSON);
+
+ String expectedMessage = String.format(PinCommand.MESSAGE_PIN_PERSON_SUCCESS,
+ Messages.formatShort(personToPin));
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel.pinPerson(personToPin);
+
+ assertCommandSuccess(pinCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_invalidIndexUnfilteredList_throwsCommandException() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
+ PinCommand pinCommand = new PinCommand(outOfBoundIndex);
+
+ assertCommandFailure(pinCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void execute_duplicatePerson_throwsCommandException() {
+ Person validPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ PinCommand pinCommand = new PinCommand(INDEX_FIRST_PERSON);
+ ModelManager filledModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ filledModel.pinPerson(validPerson);
+
+ assertThrows(CommandException.class,
+ PinCommand.MESSAGE_ALREADY_PINNED, () -> pinCommand.execute(filledModel));
+ }
+
+
+ @Test
+ public void equals() {
+ PinCommand pinFirstCommand = new PinCommand(INDEX_FIRST_PERSON);
+ PinCommand pinSecondCommand = new PinCommand(INDEX_SECOND_PERSON);
+
+ // same object -> returns true
+ assertTrue(pinFirstCommand.equals(pinFirstCommand));
+
+ // same values -> returns true
+ PinCommand duplicatepinFirstCommand = new PinCommand(INDEX_FIRST_PERSON);
+ assertTrue(pinFirstCommand.equals(duplicatepinFirstCommand));
+
+ // null -> returns false
+ assertFalse(pinFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(pinFirstCommand.equals(pinSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ PinCommand pinCommand = new PinCommand(INDEX_FIRST_PERSON);
+ String expected = PinCommand.class.getCanonicalName() + "{targetIndex=" + INDEX_FIRST_PERSON + "}";
+ assertEquals(expected, pinCommand.toString());
+ }
+
+}
diff --git a/src/test/java/bizbook/logic/commands/RedoCommandTest.java b/src/test/java/bizbook/logic/commands/RedoCommandTest.java
new file mode 100644
index 00000000000..15a62dc60b2
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/RedoCommandTest.java
@@ -0,0 +1,75 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code RedoCommand}.
+ */
+public class RedoCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_redo_throwsCommandException() {
+ RedoCommand redoCommand = new RedoCommand();
+
+ assertThrows(CommandException.class, RedoCommand.MESSAGE_REDO_FAILURE, () -> redoCommand.execute(model));
+ }
+
+ @Test
+ public void redoList_clear_afterCommit() throws CommandException {
+ RedoCommand redoCommand = new RedoCommand();
+
+ // Here we need to call undo function and then call another function for this test case
+ DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+
+ deleteCommand.execute(model);
+ model.saveAddressBookVersion();
+
+ UndoCommand undoCommand = new UndoCommand();
+ undoCommand.execute(model);
+
+ deleteCommand.execute(model);
+ model.saveAddressBookVersion();
+
+ assertThrows(CommandException.class, RedoCommand.MESSAGE_REDO_FAILURE, () -> redoCommand.execute(model));
+ }
+
+ @Test
+ public void execute_redo_success() throws CommandException {
+ DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+
+ deleteCommand.execute(model);
+ model.saveAddressBookVersion();
+
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+
+ UndoCommand undoCommand = new UndoCommand();
+ undoCommand.execute(model);
+
+ RedoCommand redoCommand = new RedoCommand();
+ assertCommandSuccess(redoCommand, model, RedoCommand.MESSAGE_REDO_SUCCESS, expectedModel);
+ }
+
+ @Test
+ public void equals() {
+ RedoCommand redoFirstCommand = new RedoCommand();
+ RedoCommand redoSecondCommand = new RedoCommand();
+
+ assertTrue(redoFirstCommand.equals(redoFirstCommand));
+ assertTrue(redoFirstCommand.equals(redoSecondCommand));
+
+ assertFalse(redoFirstCommand.equals(null));
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/ToggleCommandTest.java b/src/test/java/bizbook/logic/commands/ToggleCommandTest.java
new file mode 100644
index 00000000000..f753a08993a
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/ToggleCommandTest.java
@@ -0,0 +1,41 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+
+/**
+ * Contains unit tests for {@code ToggleCommand}.
+ */
+public class ToggleCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_toggle_success() throws CommandException {
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+
+ ToggleCommand toggleCommand = new ToggleCommand();
+
+ assertCommandSuccess(toggleCommand, model, ToggleCommand.MESSAGE_TOGGLE_SUCCESS, expectedModel);
+ }
+
+ @Test
+ public void equals() {
+ ToggleCommand toggleFirstCommand = new ToggleCommand();
+ ToggleCommand toggleSecondCommand = new ToggleCommand();
+
+ assertEquals(toggleFirstCommand, toggleFirstCommand);
+ assertTrue(toggleFirstCommand.equals(toggleSecondCommand));
+
+ assertFalse(toggleFirstCommand.equals(null));
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/UndoCommandTest.java b/src/test/java/bizbook/logic/commands/UndoCommandTest.java
new file mode 100644
index 00000000000..5a2c892bc7f
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/UndoCommandTest.java
@@ -0,0 +1,53 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.exceptions.CommandException;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+
+/**
+ * Contains integration tests (interaction with the Model) for {@code UndoCommand}.
+ */
+public class UndoCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_undo_throwsCommandException() {
+ UndoCommand undoCommand = new UndoCommand();
+
+ assertThrows(CommandException.class, UndoCommand.MESSAGE_UNDO_FAILURE, () -> undoCommand.execute(model));
+ }
+
+ @Test
+ public void execute_undo_success() throws CommandException {
+ ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+
+ DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+
+ deleteCommand.execute(model);
+ model.saveAddressBookVersion();
+
+ UndoCommand undoCommand = new UndoCommand();
+ assertCommandSuccess(undoCommand, model, UndoCommand.MESSAGE_UNDO_SUCCESS, expectedModel);
+ }
+
+ @Test
+ public void equals() {
+ UndoCommand undoFirstCommand = new UndoCommand();
+ UndoCommand undoSecondCommand = new UndoCommand();
+
+ assertTrue(undoFirstCommand.equals(undoFirstCommand));
+ assertTrue(undoFirstCommand.equals(undoSecondCommand));
+
+ assertFalse(undoFirstCommand.equals(null));
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/UnpinCommandTest.java b/src/test/java/bizbook/logic/commands/UnpinCommandTest.java
new file mode 100644
index 00000000000..4766abc0217
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/UnpinCommandTest.java
@@ -0,0 +1,79 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+import bizbook.model.person.Person;
+
+public class UnpinCommandTest {
+ private Model model;
+
+ @BeforeEach
+ public void setUp() {
+ model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ Person pinnedPerson = model.getFilteredPersonList()
+ .get(INDEX_FIRST_PERSON.getZeroBased());
+ model.pinPerson(pinnedPerson);
+ }
+
+ @Test
+ public void execute_validIndexPinnedList_success() {
+ Person personToUnpin = model.getPinnedPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ UnpinCommand unpinCommand = new UnpinCommand(INDEX_FIRST_PERSON);
+
+ String expectedMessage = String.format(UnpinCommand.MESSAGE_UNPIN_PERSON_SUCCESS,
+ Messages.formatShort(personToUnpin));
+
+ ModelManager expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ assertCommandSuccess(unpinCommand, model, expectedMessage, expectedModel);
+ }
+
+ @Test
+ public void execute_invalidIndexPinnedList_throwsCommandException() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getPinnedPersonList().size() + 1);
+ UnpinCommand unpinCommand = new UnpinCommand(outOfBoundIndex);
+
+ assertCommandFailure(unpinCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void equals() {
+ UnpinCommand unpinFirstCommand = new UnpinCommand(INDEX_FIRST_PERSON);
+ UnpinCommand unpinSecondCommand = new UnpinCommand(INDEX_SECOND_PERSON);
+
+ // same object -> returns true
+ assertTrue(unpinFirstCommand.equals(unpinFirstCommand));
+
+ // same values -> returns true
+ UnpinCommand duplicateUnpinFirstCommand = new UnpinCommand(INDEX_FIRST_PERSON);
+ assertTrue(unpinFirstCommand.equals(duplicateUnpinFirstCommand));
+
+ // null -> returns false
+ assertFalse(unpinFirstCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(unpinFirstCommand.equals(unpinSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ UnpinCommand unpinCommand = new UnpinCommand(INDEX_FIRST_PERSON);
+ String expected = UnpinCommand.class.getCanonicalName() + "{targetIndex=" + INDEX_FIRST_PERSON + "}";
+ assertEquals(expected, unpinCommand.toString());
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/ViewCommandTest.java b/src/test/java/bizbook/logic/commands/ViewCommandTest.java
new file mode 100644
index 00000000000..58f67b37954
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/ViewCommandTest.java
@@ -0,0 +1,72 @@
+package bizbook.logic.commands;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandFailure;
+import static bizbook.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static bizbook.logic.commands.ViewCommand.MESSAGE_VIEW_PERSON_SUCCESS;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalPersons.ALICE;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.model.Model;
+import bizbook.model.ModelManager;
+import bizbook.model.UserPrefs;
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for
+ * {@code ViewCommand}.
+ */
+public class ViewCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_view_success() {
+ expectedModel.getFocusedPerson().set(ALICE);
+
+ CommandResult expectedCommandResult = new CommandResult(String.format(MESSAGE_VIEW_PERSON_SUCCESS,
+ INDEX_FIRST_PERSON.getOneBased()), false, false);
+ assertCommandSuccess(new ViewCommand(INDEX_FIRST_PERSON), model, expectedCommandResult, expectedModel);
+ }
+
+ @Test
+ public void execute_view_failure() {
+ assertCommandFailure(new ViewCommand(INDEX_OUTOFBOUND_PERSON), model, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void equals() {
+ ViewCommand firstViewCommand = new ViewCommand(INDEX_FIRST_PERSON);
+ ViewCommand secondViewCommand = new ViewCommand(INDEX_SECOND_PERSON);
+
+ // same object -> returns true
+ assertTrue(firstViewCommand.equals(firstViewCommand));
+
+ // same values -> returns true
+ ViewCommand firstViewCommandCopy = new ViewCommand(INDEX_FIRST_PERSON);
+ assertTrue(firstViewCommand.equals(firstViewCommandCopy));
+
+ // different types -> returns false
+ assertFalse(firstViewCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(firstViewCommand.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstViewCommand.equals(secondViewCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ ViewCommand firstViewCommand = new ViewCommand(INDEX_FIRST_PERSON);
+ String firstViewExpected = ViewCommand.class.getCanonicalName() + "{targetIndex=" + INDEX_FIRST_PERSON + "}";
+ assertEquals(firstViewExpected, firstViewCommand.toString());
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/exporter/CsvExporterTest.java b/src/test/java/bizbook/logic/commands/exporter/CsvExporterTest.java
new file mode 100644
index 00000000000..efb9db5cf15
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/exporter/CsvExporterTest.java
@@ -0,0 +1,102 @@
+package bizbook.logic.commands.exporter;
+
+import static bizbook.logic.commands.exporter.Exporter.MESSAGE_EMPTY_ADDRESS_BOOK;
+import static bizbook.testutil.TypicalPersons.AMY;
+import static bizbook.testutil.TypicalPersons.BOB;
+import static bizbook.testutil.TypicalPersons.CHARLIE;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import bizbook.commons.util.FileUtil;
+import bizbook.logic.commands.exporter.exceptions.InvalidAddressBookException;
+import bizbook.model.AddressBook;
+import bizbook.model.UserPrefs;
+import bizbook.testutil.TestUtil;
+
+public class CsvExporterTest {
+ private static final String CHARLIE_VCF_FILE_PATH = "CsvExporterTest/charlie.csv";
+ private static final String PEOPLE_VCF_FILE_PATH = "CsvExporterTest/people.csv";
+
+ @TempDir
+ public Path temporaryFolder;
+
+ private CsvExporter csvExporter;
+
+ @BeforeEach
+ public void setUp() {
+ UserPrefs userPrefs = new UserPrefs();
+ userPrefs.setExportDirectoryPath(temporaryFolder.resolve("exports"));
+ csvExporter = new CsvExporter(userPrefs);
+ }
+
+ @Test
+ public void export_empty_throwsEmptyAddressBookException() {
+ // Assert that the file does not exist at first
+ Path exportPath = csvExporter.getExportPath();
+ assertFalse(FileUtil.isFileExists(exportPath));
+
+ AddressBook addressBook = new AddressBook();
+ assertThrows(InvalidAddressBookException.class, () -> csvExporter.exportAddressBook(addressBook),
+ MESSAGE_EMPTY_ADDRESS_BOOK);
+ assertFalse(FileUtil.isFileExists(exportPath));
+ }
+
+ @Test
+ public void export_onePerson_createsPersonVcf() {
+ // Assert that the file does not exist at first
+ Path exportPath = csvExporter.getExportPath();
+ assertFalse(FileUtil.isFileExists(exportPath));
+
+ // Export creates a file with the person's details
+ AddressBook addressBook = new AddressBook();
+ addressBook.addPerson(CHARLIE);
+ assertDoesNotThrow(() -> csvExporter.exportAddressBook(addressBook));
+
+ // Assert that the file exists now
+ assertTrue(FileUtil.isFileExists(exportPath));
+ try {
+ String expectedValue = TestUtil.readResourceFile(CsvExporterTest.class, CHARLIE_VCF_FILE_PATH);
+ String actualValue = FileUtil.readFromFile(exportPath);
+
+ assertEquals(expectedValue, actualValue);
+ } catch (IOException ie) {
+ fail(ie);
+ }
+ }
+
+ @Test
+ public void export_multiplePeople_createsPeopleVcf() {
+ // Assert that the file does not exist at first
+ Path exportPath = csvExporter.getExportPath();
+ assertFalse(FileUtil.isFileExists(exportPath));
+
+ // Export creates a file with the person's details
+ AddressBook addressBook = new AddressBook();
+ addressBook.addPerson(AMY);
+ addressBook.addPerson(BOB);
+ addressBook.addPerson(CHARLIE);
+ assertDoesNotThrow(() -> csvExporter.exportAddressBook(addressBook));
+
+ // Assert that the file exists now
+ assertTrue(FileUtil.isFileExists(exportPath));
+ try {
+ String expectedValue = TestUtil.readResourceFile(CsvExporterTest.class, PEOPLE_VCF_FILE_PATH);
+ String actualValue = FileUtil.readFromFile(exportPath);
+
+ assertEquals(expectedValue, actualValue);
+ } catch (IOException ie) {
+ fail(ie);
+ }
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/exporter/VcfExporterTest.java b/src/test/java/bizbook/logic/commands/exporter/VcfExporterTest.java
new file mode 100644
index 00000000000..f327b4bbd2c
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/exporter/VcfExporterTest.java
@@ -0,0 +1,119 @@
+package bizbook.logic.commands.exporter;
+
+import static bizbook.logic.commands.exporter.Exporter.MESSAGE_EMPTY_ADDRESS_BOOK;
+import static bizbook.testutil.TypicalPersons.AMY;
+import static bizbook.testutil.TypicalPersons.BOB;
+import static bizbook.testutil.TypicalPersons.CHARLIE;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import bizbook.commons.util.FileUtil;
+import bizbook.logic.commands.exporter.exceptions.InvalidAddressBookException;
+import bizbook.model.AddressBook;
+import bizbook.model.UserPrefs;
+import bizbook.testutil.TestUtil;
+import ezvcard.Ezvcard;
+import ezvcard.VCard;
+
+public class VcfExporterTest {
+ private static final String CHARLIE_VCF_FILE_PATH = "VcfExporterTest/charlie.vcf";
+ private static final String PEOPLE_VCF_FILE_PATH = "VcfExporterTest/people.vcf";
+
+ @TempDir
+ public Path temporaryFolder;
+
+ private VcfExporter vcfExporter;
+
+ @BeforeEach
+ public void setUp() {
+ UserPrefs userPrefs = new UserPrefs();
+ userPrefs.setExportDirectoryPath(temporaryFolder.resolve("exports"));
+ vcfExporter = new VcfExporter(userPrefs);
+ }
+
+ @Test
+ public void export_empty_throwsEmptyAddressBookException() {
+ // Assert that the file does not exist at first
+ Path exportPath = vcfExporter.getExportPath();
+ assertFalse(FileUtil.isFileExists(exportPath));
+
+ AddressBook addressBook = new AddressBook();
+ assertThrows(InvalidAddressBookException.class, () -> vcfExporter.exportAddressBook(addressBook),
+ MESSAGE_EMPTY_ADDRESS_BOOK);
+ assertFalse(FileUtil.isFileExists(exportPath));
+ }
+
+ @Test
+ public void export_onePerson_createsPersonVcf() {
+ // Assert that the file does not exist at first
+ Path exportPath = vcfExporter.getExportPath();
+ assertFalse(FileUtil.isFileExists(exportPath));
+
+ // Export creates a file with the person's details
+ AddressBook addressBook = new AddressBook();
+ addressBook.addPerson(CHARLIE);
+ assertDoesNotThrow(() -> vcfExporter.exportAddressBook(addressBook));
+
+ // Assert that the file exists now
+ assertTrue(FileUtil.isFileExists(exportPath));
+ try {
+ String expectedValue = TestUtil.readResourceFile(VcfExporterTest.class, CHARLIE_VCF_FILE_PATH);
+ String actualValue = FileUtil.readFromFile(exportPath);
+
+ assertEquals(expectedValue, actualValue);
+ } catch (IOException ie) {
+ fail(ie);
+ }
+ }
+
+ @Test
+ public void export_multiplePeople_createsPeopleVcf() {
+ // Assert that the file does not exist at first
+ Path exportPath = vcfExporter.getExportPath();
+ assertFalse(FileUtil.isFileExists(exportPath));
+
+ // Export creates a file with the person's details
+ AddressBook addressBook = new AddressBook();
+ addressBook.addPerson(AMY);
+ addressBook.addPerson(BOB);
+ addressBook.addPerson(CHARLIE);
+ assertDoesNotThrow(() -> vcfExporter.exportAddressBook(addressBook));
+
+ // Assert that the file exists now
+ assertTrue(FileUtil.isFileExists(exportPath));
+ try {
+ String expectedValue = TestUtil.readResourceFile(VcfExporterTest.class, PEOPLE_VCF_FILE_PATH);
+ String actualValue = FileUtil.readFromFile(exportPath);
+
+ assertEquals(expectedValue, actualValue);
+ } catch (IOException ie) {
+ fail(ie);
+ }
+ }
+
+ @Test
+ public void export_multiplePeople_isValidVcf() throws IOException, InvalidAddressBookException {
+ vcfExporter.exportAddressBook(getTypicalAddressBook());
+
+ Path exportPath = vcfExporter.getExportPath();
+ String contents = FileUtil.readFromFile(exportPath);
+ List vCards = Ezvcard.parse(contents).all();
+
+ for (VCard vCard : vCards) {
+ assertTrue(vCard.validate(vCard.getVersion()).isEmpty());
+ }
+ }
+}
diff --git a/src/test/java/bizbook/logic/commands/exporter/VcfImporterTest.java b/src/test/java/bizbook/logic/commands/exporter/VcfImporterTest.java
new file mode 100644
index 00000000000..9a23b364164
--- /dev/null
+++ b/src/test/java/bizbook/logic/commands/exporter/VcfImporterTest.java
@@ -0,0 +1,109 @@
+package bizbook.logic.commands.exporter;
+
+import static bizbook.logic.commands.exporter.VcfImporter.MESSAGE_EMPTY_FILE;
+import static bizbook.logic.commands.exporter.VcfImporter.MESSAGE_INVALID_FORMAT;
+import static bizbook.logic.commands.exporter.VcfImporter.MESSAGE_INVALID_INFORMATION;
+import static bizbook.logic.commands.exporter.VcfImporter.MESSAGE_MISSING_INFORMATION;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.CHARLIE;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.exporter.exceptions.InvalidFileException;
+import bizbook.model.AddressBook;
+import bizbook.testutil.TestUtil;
+
+public class VcfImporterTest {
+ private static final String TYPICAL_VCF_FILE_PATH = "VcfImporterTest/typical.vcf";
+ private static final String SINGLE_VCF_FILE_PATH = "VcfImporterTest/single.vcf";
+ private static final String EMPTY_VCF_FILE_PATH = "VcfImporterTest/empty.vcf";
+ private static final String WRONG_FORMAT_FILE_PATH = "VcfImporterTest/wrong_format.vcf";
+ private static final String MISSING_INFO_FILE_PATH = "VcfImporterTest/missing_info.vcf";
+ private static final String INVALID_INFO_FILE_PATH = "VcfImporterTest/invalid_info.vcf";
+
+ private VcfImporter vcfImporter;
+
+ private Path convertToRelative(Path absolutePath) {
+ Path currentPath = Paths.get(".").toAbsolutePath();
+ return currentPath.relativize(absolutePath);
+ }
+
+ @BeforeEach
+ public void setUp() {
+ vcfImporter = new VcfImporter();
+ }
+
+ @Test
+ public void import_fullPath_success() throws IOException, InvalidFileException {
+ Path path = TestUtil.getResourceFilePath(VcfImporterTest.class, TYPICAL_VCF_FILE_PATH);
+ assertTrue(path.isAbsolute());
+
+ AddressBook expectedAddressBook = getTypicalAddressBook();
+ AddressBook actualAddressBook = vcfImporter.importAddressBook(path);
+
+ assertEquals(expectedAddressBook, actualAddressBook);
+ }
+
+ @Test
+ public void import_relativePath_success() throws IOException, InvalidFileException {
+ // Convert absolute path to be relative to current directory
+ Path path = convertToRelative(
+ TestUtil.getResourceFilePath(VcfImporter.class, TYPICAL_VCF_FILE_PATH));
+ assertFalse(path.isAbsolute());
+
+ AddressBook expectedAddressBook = getTypicalAddressBook();
+ AddressBook actualAddressBook = vcfImporter.importAddressBook(path);
+
+ assertEquals(expectedAddressBook, actualAddressBook);
+ }
+
+ @Test
+ public void import_single_success() throws IOException, InvalidFileException {
+ Path path = TestUtil.getResourceFilePath(VcfImporterTest.class, SINGLE_VCF_FILE_PATH);
+
+ AddressBook expectedAddressBook = new AddressBook();
+ expectedAddressBook.addPerson(CHARLIE);
+ AddressBook actualAddressBook = vcfImporter.importAddressBook(path);
+
+ assertEquals(expectedAddressBook, actualAddressBook);
+ }
+
+ @Test
+ public void import_empty_throwsEmptyAddressBookException() {
+ Path path = TestUtil.getResourceFilePath(VcfImporterTest.class, EMPTY_VCF_FILE_PATH);
+
+ assertThrows(InvalidFileException.class, MESSAGE_EMPTY_FILE, () -> vcfImporter.importAddressBook(path));
+ }
+
+ @Test
+ public void import_wrongFormat_throwsInvalidFileException() {
+ Path path = TestUtil.getResourceFilePath(VcfImporterTest.class, WRONG_FORMAT_FILE_PATH);
+
+ assertThrows(InvalidFileException.class, MESSAGE_INVALID_FORMAT, () -> vcfImporter.importAddressBook(path));
+ }
+
+ @Test
+ public void import_missingInformation_throwsInvalidFileException() {
+ Path path = TestUtil.getResourceFilePath(VcfImporterTest.class, MISSING_INFO_FILE_PATH);
+
+ assertThrows(InvalidFileException.class, MESSAGE_MISSING_INFORMATION, () ->
+ vcfImporter.importAddressBook(path));
+ }
+
+ @Test
+ public void import_invalidInformation_throwsInvalidFileException() {
+ Path path = TestUtil.getResourceFilePath(VcfImporterTest.class, INVALID_INFO_FILE_PATH);
+
+ assertThrows(InvalidFileException.class, MESSAGE_INVALID_INFORMATION, () ->
+ vcfImporter.importAddressBook(path));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/bizbook/logic/parser/AddCommandParserTest.java
similarity index 70%
rename from src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
rename to src/test/java/bizbook/logic/parser/AddCommandParserTest.java
index 5bc11d3cdaa..36771762795 100644
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ b/src/test/java/bizbook/logic/parser/AddCommandParserTest.java
@@ -1,49 +1,49 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
-import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-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.CommandParserTestUtil.assertParseFailure;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalPersons.AMY;
-import static seedu.address.testutil.TypicalPersons.BOB;
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
+import static bizbook.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.NAME_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
+import static bizbook.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
+import static bizbook.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
+import static bizbook.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalPersons.AMY;
+import static bizbook.testutil.TypicalPersons.BOB;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.Messages;
-import seedu.address.logic.commands.AddCommand;
-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 seedu.address.testutil.PersonBuilder;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.AddCommand;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
+import bizbook.testutil.PersonBuilder;
public class AddCommandParserTest {
private AddCommandParser parser = new AddCommandParser();
@@ -54,7 +54,7 @@ public void parse_allFieldsPresent_success() {
// whitespace only preamble
assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
+ + ADDRESS_DESC_BOB + TAG_DESC_FRIEND + "", new AddCommand(expectedPerson));
// multiple tags - all accepted
diff --git a/src/test/java/bizbook/logic/parser/AddNoteCommandParserTest.java b/src/test/java/bizbook/logic/parser/AddNoteCommandParserTest.java
new file mode 100644
index 00000000000..4d957052046
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/AddNoteCommandParserTest.java
@@ -0,0 +1,48 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.commands.AddNoteCommand.MESSAGE_USAGE;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.AddNoteCommand;
+import bizbook.model.person.Note;
+
+public class AddNoteCommandParserTest {
+
+ private static final String ADDNOTE_INVALID_FORMAT = "Invalid command format! \n" + MESSAGE_USAGE;
+
+ private AddNotesCommandParser parser = new AddNotesCommandParser();
+
+
+ @Test
+ public void parse_validArgs_success() {
+
+ // Note with index
+ assertParseSuccess(parser, "1 n/note1",
+ new AddNoteCommand(Index.fromOneBased(1), new Note("note1")));
+
+ }
+
+ @Test
+ public void parse_invalidArgs_failure() {
+
+ // Non alphanumerical note
+ assertParseFailure(parser, "1 n/note!", ADDNOTE_INVALID_FORMAT);
+
+ // Invalid index
+ assertParseFailure(parser, "-1 n/note1", ADDNOTE_INVALID_FORMAT);
+
+ // No index
+ assertParseFailure(parser, "n/note!", ADDNOTE_INVALID_FORMAT);
+
+ // No note
+ assertParseFailure(parser, "1 n/", ADDNOTE_INVALID_FORMAT);
+
+ // No note and no index
+ assertParseFailure(parser, "", ADDNOTE_INVALID_FORMAT);
+
+ }
+}
diff --git a/src/test/java/bizbook/logic/parser/AddressBookParserTest.java b/src/test/java/bizbook/logic/parser/AddressBookParserTest.java
new file mode 100644
index 00000000000..2ffa8174ca7
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/AddressBookParserTest.java
@@ -0,0 +1,203 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_CSV;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.AddCommand;
+import bizbook.logic.commands.ClearCommand;
+import bizbook.logic.commands.DeleteCommand;
+import bizbook.logic.commands.DeleteTagCommand;
+import bizbook.logic.commands.EditCommand;
+import bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.logic.commands.ExitCommand;
+import bizbook.logic.commands.ExportCommand;
+import bizbook.logic.commands.FindCommand;
+import bizbook.logic.commands.HelpCommand;
+import bizbook.logic.commands.ListCommand;
+import bizbook.logic.commands.PinCommand;
+import bizbook.logic.commands.RedoCommand;
+import bizbook.logic.commands.UndoCommand;
+import bizbook.logic.commands.UnpinCommand;
+import bizbook.logic.commands.ViewCommand;
+import bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.NameContainsKeywordsPredicate;
+import bizbook.model.person.Person;
+import bizbook.model.tag.Tag;
+import bizbook.testutil.EditPersonDescriptorBuilder;
+import bizbook.testutil.PersonBuilder;
+import bizbook.testutil.PersonUtil;
+
+public class AddressBookParserTest {
+
+ private final AddressBookParser parser = new AddressBookParser();
+
+ @Test
+ public void parseCommand_add() throws Exception {
+ Person person = new PersonBuilder().build();
+ AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person));
+ AddCommand commandUpperCase = (AddCommand) parser.parseCommand(
+ AddCommand.COMMAND_WORD.toUpperCase() + " " + PersonUtil.getPersonDetails(person));
+ assertEquals(new AddCommand(person), command);
+ assertEquals(new AddCommand(person), commandUpperCase);
+ }
+
+
+ @Test
+ public void parseCommand_clear() throws Exception {
+ assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand);
+ assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD.toUpperCase()) instanceof ClearCommand);
+ assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand);
+ assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD.toUpperCase() + " 3") instanceof ClearCommand);
+ }
+
+ @Test
+ public void parseCommand_delete() throws Exception {
+ DeleteCommand command = (DeleteCommand) parser.parseCommand(
+ DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
+ DeleteCommand commandUpperCase = (DeleteCommand) parser.parseCommand(
+ DeleteCommand.COMMAND_WORD.toUpperCase() + " " + INDEX_FIRST_PERSON.getOneBased());
+ assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
+ assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_edit() throws Exception {
+ Person person = new PersonBuilder().build();
+ EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
+ EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
+ + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
+ EditCommand commandUpperCase = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD.toUpperCase() + " "
+ + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
+ assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
+ assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_deleteTag() throws Exception {
+ DeleteTagCommand command = (DeleteTagCommand) parser.parseCommand(
+ DeleteTagCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased()
+ + " " + PREFIX_TAG + VALID_TAG_FRIEND);
+ DeleteTagCommand commandUpperCase = (DeleteTagCommand) parser.parseCommand(
+ DeleteTagCommand.COMMAND_WORD.toUpperCase() + " " + INDEX_FIRST_PERSON.getOneBased()
+ + " " + PREFIX_TAG + VALID_TAG_FRIEND);
+ assertEquals(new DeleteTagCommand(INDEX_FIRST_PERSON, new Tag(VALID_TAG_FRIEND)), command);
+ assertEquals(new DeleteTagCommand(INDEX_FIRST_PERSON, new Tag(VALID_TAG_FRIEND)), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_exit() throws Exception {
+ assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand);
+ assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD.toUpperCase()) instanceof ExitCommand);
+ assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand);
+ assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD.toUpperCase() + " 3") instanceof ExitCommand);
+ }
+
+ @Test
+ public void parseCommand_find() throws Exception {
+ List keywords = Arrays.asList("foo", "bar", "baz");
+ FindCommand command = (FindCommand) parser.parseCommand(
+ FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
+ FindCommand commandUpperCase = (FindCommand) parser.parseCommand(FindCommand.COMMAND_WORD.toUpperCase()
+ + " " + keywords.stream().collect(Collectors.joining(" ")));
+ assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
+ assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_help() throws Exception {
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD.toUpperCase()) instanceof HelpCommand);
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand);
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD.toUpperCase() + " 3") instanceof HelpCommand);
+ }
+
+ @Test
+ public void parseCommand_list() throws Exception {
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD.toUpperCase()) instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD.toUpperCase() + " 3") instanceof ListCommand);
+ }
+
+ @Test
+ public void parseCommand_view() throws Exception {
+ assertTrue(parser.parseCommand(ViewCommand.COMMAND_WORD + " "
+ + INDEX_FIRST_PERSON.getOneBased()) instanceof ViewCommand);
+ assertTrue(parser.parseCommand(ViewCommand.COMMAND_WORD.toUpperCase()
+ + " " + INDEX_FIRST_PERSON.getOneBased()) instanceof ViewCommand);
+ }
+
+ @Test
+ public void parseCommand_export() throws Exception {
+ ExportCommand command = (ExportCommand) parser.parseCommand(
+ ExportCommand.COMMAND_WORD + " " + CliSyntax.PREFIX_FILE + FILE_TYPE_CSV);
+ ExportCommand commandUpperCase = (ExportCommand) parser.parseCommand(
+ ExportCommand.COMMAND_WORD.toUpperCase() + " " + CliSyntax.PREFIX_FILE + FILE_TYPE_CSV);
+ assertEquals(new ExportCommand(FILE_TYPE_CSV), command);
+ assertEquals(new ExportCommand(FILE_TYPE_CSV), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_pin() throws Exception {
+ PinCommand command = (PinCommand) parser.parseCommand(
+ PinCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
+ PinCommand commandUpperCase = (PinCommand) parser.parseCommand(
+ PinCommand.COMMAND_WORD.toUpperCase() + " " + INDEX_FIRST_PERSON.getOneBased());
+ assertEquals(new PinCommand(INDEX_FIRST_PERSON), command);
+ assertEquals(new PinCommand(INDEX_FIRST_PERSON), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_unpin() throws Exception {
+ UnpinCommand command = (UnpinCommand) parser.parseCommand(
+ UnpinCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
+ UnpinCommand commandUpperCase = (UnpinCommand) parser.parseCommand(
+ UnpinCommand.COMMAND_WORD.toUpperCase() + " " + INDEX_FIRST_PERSON.getOneBased());
+ assertEquals(new UnpinCommand(INDEX_FIRST_PERSON), command);
+ assertEquals(new UnpinCommand(INDEX_FIRST_PERSON), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_undo() throws Exception {
+ UndoCommand command = (UndoCommand) parser.parseCommand(
+ UndoCommand.COMMAND_WORD);
+ UndoCommand commandUpperCase = (UndoCommand) parser.parseCommand(
+ UndoCommand.COMMAND_WORD.toUpperCase());
+ assertEquals(new UndoCommand(), command);
+ assertEquals(new UndoCommand(), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_redo() throws Exception {
+ RedoCommand command = (RedoCommand) parser.parseCommand(
+ RedoCommand.COMMAND_WORD);
+ RedoCommand commandUpperCase = (RedoCommand) parser.parseCommand(
+ RedoCommand.COMMAND_WORD.toUpperCase());
+ assertEquals(new RedoCommand(), command);
+ assertEquals(new RedoCommand(), commandUpperCase);
+ }
+
+ @Test
+ public void parseCommand_unrecognisedInput_throwsParseException() {
+ assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
+ -> parser.parseCommand(""));
+ }
+
+ @Test
+ public void parseCommand_unknownCommand_throwsParseException() {
+ assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java b/src/test/java/bizbook/logic/parser/ArgumentTokenizerTest.java
similarity index 99%
rename from src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java
rename to src/test/java/bizbook/logic/parser/ArgumentTokenizerTest.java
index c97308935f5..c76d9cb6516 100644
--- a/src/test/java/seedu/address/logic/parser/ArgumentTokenizerTest.java
+++ b/src/test/java/bizbook/logic/parser/ArgumentTokenizerTest.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
diff --git a/src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java b/src/test/java/bizbook/logic/parser/CommandParserTestUtil.java
similarity index 89%
rename from src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java
rename to src/test/java/bizbook/logic/parser/CommandParserTestUtil.java
index 9bf1ccf1cef..bf44bfd50dc 100644
--- a/src/test/java/seedu/address/logic/parser/CommandParserTestUtil.java
+++ b/src/test/java/bizbook/logic/parser/CommandParserTestUtil.java
@@ -1,9 +1,9 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.parser.exceptions.ParseException;
+import bizbook.logic.commands.Command;
+import bizbook.logic.parser.exceptions.ParseException;
/**
* Contains helper methods for testing command parsers.
diff --git a/src/test/java/bizbook/logic/parser/DeleteCommandParserTest.java b/src/test/java/bizbook/logic/parser/DeleteCommandParserTest.java
new file mode 100644
index 00000000000..e311e8eaa4b
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/DeleteCommandParserTest.java
@@ -0,0 +1,45 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.DeleteCommand;
+
+/**
+ * As we are only doing white-box testing, our test cases do not cover path variations
+ * outside of the DeleteCommand code. For example, inputs "1" and "1 abc" take the
+ * same path through the DeleteCommand, and therefore we test only one of them.
+ * The path variation for those two cases occur inside the ParserUtil, and
+ * therefore should be covered by the ParserUtilTest.
+ */
+public class DeleteCommandParserTest {
+
+ private DeleteCommandParser parser = new DeleteCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsDeleteCommand() {
+ assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
+ }
+
+ @Test
+ public void parse_outOfBound_returnsDeleteCommand() {
+ // handling of out of bound person is done by delete command,
+ // as 1000 is still considered a positive integer.
+ assertParseSuccess(parser, "1000", new DeleteCommand(INDEX_OUTOFBOUND_PERSON));
+ }
+
+ @Test
+ public void parse_nonInteger_throwsParseException() {
+ assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonPositiveInteger_throwsParseException() {
+ assertParseFailure(parser, "-1", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/bizbook/logic/parser/DeleteNoteCommandParserTest.java b/src/test/java/bizbook/logic/parser/DeleteNoteCommandParserTest.java
new file mode 100644
index 00000000000..ce960f0a55c
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/DeleteNoteCommandParserTest.java
@@ -0,0 +1,46 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.commands.DeleteNoteCommand.MESSAGE_USAGE;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.core.index.Index;
+import bizbook.logic.commands.DeleteNoteCommand;
+
+public class DeleteNoteCommandParserTest {
+
+ private static final String DELETENOTE_INVALID_FORMAT = "Invalid command format! \n" + MESSAGE_USAGE;
+
+ private DeleteNotesCommandParser parser = new DeleteNotesCommandParser();
+
+ @Test
+ public void parse_validArgs_success() {
+
+ // Valid index and note index
+ assertParseSuccess(parser, "1 i/1",
+ new DeleteNoteCommand(Index.fromOneBased(1), Index.fromOneBased(1)));
+
+ }
+
+ @Test
+ public void parse_invalidArgs_failure() {
+
+ // Invalid index
+ assertParseFailure(parser, "-1 i/1", DELETENOTE_INVALID_FORMAT);
+
+ // Invalid note index
+ assertParseFailure(parser, "1 i/-1", DELETENOTE_INVALID_FORMAT);
+
+ // No index
+ assertParseFailure(parser, "i/1", DELETENOTE_INVALID_FORMAT);
+
+ // No note index
+ assertParseFailure(parser, "-1 i/", DELETENOTE_INVALID_FORMAT);
+
+ // No note and no index
+ assertParseFailure(parser, "", DELETENOTE_INVALID_FORMAT);
+
+ }
+}
diff --git a/src/test/java/bizbook/logic/parser/DeleteTagCommandParserTest.java b/src/test/java/bizbook/logic/parser/DeleteTagCommandParserTest.java
new file mode 100644
index 00000000000..dd2593da5ad
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/DeleteTagCommandParserTest.java
@@ -0,0 +1,41 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.DeleteTagCommand;
+import bizbook.model.tag.Tag;
+
+public class DeleteTagCommandParserTest {
+ private DeleteTagCommandParser parser = new DeleteTagCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsDeleteTagCommand() {
+ assertParseSuccess(parser, " 1 " + PREFIX_TAG + VALID_TAG_FRIEND,
+ new DeleteTagCommand(INDEX_FIRST_PERSON, new Tag(VALID_TAG_FRIEND)));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ assertParseFailure(parser, "", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTagCommand.MESSAGE_USAGE));
+
+ assertParseFailure(parser, "-1 ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTagCommand.MESSAGE_USAGE));
+
+ // Invalid prefix
+ assertParseFailure(parser, " 1 " + PREFIX_NAME + "Burnice", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTagCommand.MESSAGE_USAGE));
+
+ // Invalid tag
+ assertParseFailure(parser, " 1 " + PREFIX_TAG + "@", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteTagCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/bizbook/logic/parser/EditCommandParserTest.java
similarity index 71%
rename from src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
rename to src/test/java/bizbook/logic/parser/EditCommandParserTest.java
index cc7175172d4..9552f0a4ba4 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/bizbook/logic/parser/EditCommandParserTest.java
@@ -1,56 +1,56 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
+import static bizbook.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
+import static bizbook.logic.commands.CommandTestUtil.NAME_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static bizbook.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
+import static bizbook.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
+import static bizbook.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.Messages;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import bizbook.commons.core.index.Index;
+import bizbook.logic.Messages;
+import bizbook.logic.commands.EditCommand;
+import bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
+import bizbook.testutil.EditPersonDescriptorBuilder;
public class EditCommandParserTest {
private static final String TAG_EMPTY = " " + PREFIX_TAG;
- private static final String MESSAGE_INVALID_FORMAT =
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE);
+ private static final String MESSAGE_INVALID_FORMAT = String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditCommand.MESSAGE_USAGE);
private EditCommandParser parser = new EditCommandParser();
diff --git a/src/test/java/bizbook/logic/parser/EditNoteCommandParserTest.java b/src/test/java/bizbook/logic/parser/EditNoteCommandParserTest.java
new file mode 100644
index 00000000000..ed07d30cd0f
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/EditNoteCommandParserTest.java
@@ -0,0 +1,46 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NOTES_INDEX;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_NOTE;
+import static bizbook.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static bizbook.testutil.TypicalNotes.VALID_NOTE;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.EditNoteCommand;
+
+
+public class EditNoteCommandParserTest {
+
+ private static final String MESSAGE_INVALID_FORMAT = String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ EditNoteCommand.MESSAGE_USAGE);
+
+ private EditNotesCommandParser parser = new EditNotesCommandParser();
+
+ @Test
+ public void parse_missingParts_failure() {
+ // Wrong command format
+ assertParseFailure(parser, VALID_NOTE.getNote(), MESSAGE_INVALID_FORMAT);
+
+ // no field specified
+ assertParseFailure(parser, "1", MESSAGE_INVALID_FORMAT);
+
+ // no index and no field specified
+ assertParseFailure(parser, "", MESSAGE_INVALID_FORMAT);
+ }
+
+ @Test
+ public void parse_allFieldsSpecified_success() {
+ String userInput = INDEX_SECOND_PERSON.getOneBased() + " " + PREFIX_NOTES_INDEX + INDEX_FIRST_NOTE.getOneBased()
+ + " " + PREFIX_NOTES + VALID_NOTE.getNote();
+
+ EditNoteCommand expectedCommand = new EditNoteCommand(INDEX_SECOND_PERSON, INDEX_FIRST_NOTE, VALID_NOTE);
+
+ assertParseSuccess(parser, userInput, expectedCommand);
+ }
+
+}
diff --git a/src/test/java/bizbook/logic/parser/ExportCommandParserTest.java b/src/test/java/bizbook/logic/parser/ExportCommandParserTest.java
new file mode 100644
index 00000000000..dad49a25617
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/ExportCommandParserTest.java
@@ -0,0 +1,28 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CliSyntax.PREFIX_FILE;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_CSV;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.ExportCommand;
+
+
+public class ExportCommandParserTest {
+
+ private ExportCommandParser parser = new ExportCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsExportCommand() {
+ assertParseSuccess(parser, " " + PREFIX_FILE + "csv", new ExportCommand(FILE_TYPE_CSV));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, ExportCommand.MESSAGE_USAGE));
+ }
+
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/bizbook/logic/parser/FindCommandParserTest.java
similarity index 67%
rename from src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
rename to src/test/java/bizbook/logic/parser/FindCommandParserTest.java
index d92e64d12f9..d2c2021e6eb 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/bizbook/logic/parser/FindCommandParserTest.java
@@ -1,15 +1,15 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import bizbook.logic.commands.FindCommand;
+import bizbook.model.person.NameContainsKeywordsPredicate;
public class FindCommandParserTest {
diff --git a/src/test/java/bizbook/logic/parser/ImportCommandParserTest.java b/src/test/java/bizbook/logic/parser/ImportCommandParserTest.java
new file mode 100644
index 00000000000..e47d892efce
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/ImportCommandParserTest.java
@@ -0,0 +1,48 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.Messages.MESSAGE_UNSUPPORTED_FILE_TYPE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_FILE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PATH;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_CSV;
+import static bizbook.testutil.TypicalFileTypes.FILE_TYPE_VCF;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.ImportCommand;
+
+
+public class ImportCommandParserTest {
+ private final ImportCommandParser parser = new ImportCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsImportCommand() {
+ assertParseSuccess(parser, " " + PREFIX_FILE + FILE_TYPE_VCF.name() + " " + PREFIX_PATH + "a/b/c",
+ new ImportCommand(FILE_TYPE_VCF, Path.of("a/b/c")));
+ }
+
+ @Test
+ public void parse_unsupportedFileType_throwsParseException() {
+ // This premise is needed for this test to work
+ assertFalse(FILE_TYPE_CSV.hasImporter());
+
+ assertParseFailure(parser, " " + PREFIX_FILE + FILE_TYPE_CSV.name() + " " + PREFIX_PATH + "a/b/c",
+ String.format(MESSAGE_UNSUPPORTED_FILE_TYPE, ImportCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_missingArg_throwsParseException() {
+ assertParseFailure(parser, " " + PREFIX_FILE + FILE_TYPE_VCF.name(),
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/bizbook/logic/parser/ParserUtilTest.java
similarity index 90%
rename from src/test/java/seedu/address/logic/parser/ParserUtilTest.java
rename to src/test/java/bizbook/logic/parser/ParserUtilTest.java
index 4256788b1a7..eec8f56a1d5 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/bizbook/logic/parser/ParserUtilTest.java
@@ -1,24 +1,24 @@
-package seedu.address.logic.parser;
+package bizbook.logic.parser;
+import static bizbook.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
-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 bizbook.logic.parser.exceptions.ParseException;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
public class ParserUtilTest {
private static final String INVALID_NAME = "R@chel";
@@ -28,7 +28,7 @@ public class ParserUtilTest {
private static final String INVALID_TAG = "#friend";
private static final String VALID_NAME = "Rachel Walker";
- private static final String VALID_PHONE = "123456";
+ private static final String VALID_PHONE = "91234567";
private static final String VALID_ADDRESS = "123 Main Street #0505";
private static final String VALID_EMAIL = "rachel@example.com";
private static final String VALID_TAG_1 = "friend";
@@ -189,7 +189,7 @@ public void parseTags_emptyCollection_returnsEmptySet() throws Exception {
@Test
public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception {
Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, VALID_TAG_2));
- Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2)));
+ Set expectedTagSet = new LinkedHashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2)));
assertEquals(expectedTagSet, actualTagSet);
}
diff --git a/src/test/java/bizbook/logic/parser/PinCommandParserTest.java b/src/test/java/bizbook/logic/parser/PinCommandParserTest.java
new file mode 100644
index 00000000000..a12d5b7c8c0
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/PinCommandParserTest.java
@@ -0,0 +1,44 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.PinCommand;
+
+public class PinCommandParserTest {
+
+ private PinCommandParser parser = new PinCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsPinCommand() {
+ assertParseSuccess(parser, "1", new PinCommand(INDEX_FIRST_PERSON));
+ }
+
+ @Test
+ public void parse_outOfBound_returnsPinCommand() {
+ // handling of out of bound person is done by pin command,
+ // as 1000 is still considered a positive integer.
+ assertParseSuccess(parser, "1000", new PinCommand(INDEX_OUTOFBOUND_PERSON));
+ }
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, PinCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonInteger_throwsParseException() {
+ assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, PinCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonPositiveInteger_throwsParseException() {
+ assertParseFailure(parser, "-1", String.format(MESSAGE_INVALID_COMMAND_FORMAT, PinCommand.MESSAGE_USAGE));
+ }
+
+}
diff --git a/src/test/java/bizbook/logic/parser/UnpinCommandParserTest.java b/src/test/java/bizbook/logic/parser/UnpinCommandParserTest.java
new file mode 100644
index 00000000000..6bc642d465d
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/UnpinCommandParserTest.java
@@ -0,0 +1,42 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static bizbook.testutil.TypicalIndexes.INDEX_OUTOFBOUND_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.UnpinCommand;
+
+public class UnpinCommandParserTest {
+ private UnpinCommandParser parser = new UnpinCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsUnpinCommand() {
+ assertParseSuccess(parser, "1", new UnpinCommand(INDEX_FIRST_PERSON));
+ }
+
+ @Test
+ public void parse_outOfBound_returnsUnpinCommand() {
+ // handling of out of bound person is done by Unpin command,
+ // as 1000 is still considered a positive integer.
+ assertParseSuccess(parser, "1000", new UnpinCommand(INDEX_OUTOFBOUND_PERSON));
+ }
+
+ @Test
+ public void parse_emptyArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnpinCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonInteger_throwsParseException() {
+ assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnpinCommand.MESSAGE_USAGE));
+ }
+
+ @Test
+ public void parse_nonPositiveInteger_throwsParseException() {
+ assertParseFailure(parser, "-1", String.format(MESSAGE_INVALID_COMMAND_FORMAT, UnpinCommand.MESSAGE_USAGE));
+ }
+}
diff --git a/src/test/java/bizbook/logic/parser/ViewCommandParserTest.java b/src/test/java/bizbook/logic/parser/ViewCommandParserTest.java
new file mode 100644
index 00000000000..59c77ad0f9e
--- /dev/null
+++ b/src/test/java/bizbook/logic/parser/ViewCommandParserTest.java
@@ -0,0 +1,28 @@
+package bizbook.logic.parser;
+
+import static bizbook.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseFailure;
+import static bizbook.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static bizbook.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.logic.commands.ViewCommand;
+
+public class ViewCommandParserTest {
+
+ private ViewCommandParser parser = new ViewCommandParser();
+
+ @Test
+ public void parse_validArgs_returnsViewCommand() {
+ assertParseSuccess(parser, " 1", new ViewCommand(INDEX_FIRST_PERSON));
+ }
+
+ @Test
+ public void parse_invalidArgs_throwsParseException() {
+ assertParseFailure(parser, "Alex ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE));
+
+ assertParseFailure(parser, "-1 ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewCommand.MESSAGE_USAGE));
+ }
+
+}
diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/bizbook/model/AddressBookTest.java
similarity index 82%
rename from src/test/java/seedu/address/model/AddressBookTest.java
rename to src/test/java/bizbook/model/AddressBookTest.java
index 68c8c5ba4d5..057306b56e0 100644
--- a/src/test/java/seedu/address/model/AddressBookTest.java
+++ b/src/test/java/bizbook/model/AddressBookTest.java
@@ -1,13 +1,13 @@
-package seedu.address.model;
+package bizbook.model;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.ALICE;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import java.util.Arrays;
import java.util.Collection;
@@ -16,11 +16,11 @@
import org.junit.jupiter.api.Test;
+import bizbook.model.person.Person;
+import bizbook.model.person.exceptions.DuplicatePersonException;
+import bizbook.testutil.PersonBuilder;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.testutil.PersonBuilder;
public class AddressBookTest {
@@ -94,6 +94,7 @@ public void toStringMethod() {
*/
private static class AddressBookStub implements ReadOnlyAddressBook {
private final ObservableList persons = FXCollections.observableArrayList();
+ private final ObservableList pinnedPersons = FXCollections.observableArrayList();
AddressBookStub(Collection persons) {
this.persons.setAll(persons);
@@ -103,6 +104,11 @@ private static class AddressBookStub implements ReadOnlyAddressBook {
public ObservableList getPersonList() {
return persons;
}
+
+ @Override
+ public ObservableList getPinnedPersonList() {
+ return pinnedPersons;
+ }
}
}
diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/bizbook/model/ModelManagerTest.java
similarity index 79%
rename from src/test/java/seedu/address/model/ModelManagerTest.java
rename to src/test/java/bizbook/model/ModelManagerTest.java
index 2cf1418d116..4e0cc1d00eb 100644
--- a/src/test/java/seedu/address/model/ModelManagerTest.java
+++ b/src/test/java/bizbook/model/ModelManagerTest.java
@@ -1,12 +1,12 @@
-package seedu.address.model;
+package bizbook.model;
+import static bizbook.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.ALICE;
+import static bizbook.testutil.TypicalPersons.BENSON;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BENSON;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -14,9 +14,10 @@
import org.junit.jupiter.api.Test;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.testutil.AddressBookBuilder;
+import bizbook.commons.core.GuiSettings;
+import bizbook.model.person.NameContainsKeywordsPredicate;
+import bizbook.model.person.Person;
+import bizbook.testutil.AddressBookBuilder;
public class ModelManagerTest {
@@ -93,6 +94,19 @@ public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException
assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0));
}
+ @Test
+ public void setFocusPerson_success() {
+ modelManager.setFocusPerson(ALICE);
+ assertEquals(modelManager.getFocusedPerson().get(), ALICE);
+ }
+
+ @Test
+ public void updateFocusPerson_success() {
+ modelManager.setFocusPerson(ALICE);
+ modelManager.updateFocusPerson(ALICE, BENSON);
+ assertEquals(modelManager.getFocusedPerson().get(), BENSON);
+ }
+
@Test
public void equals() {
AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build();
@@ -124,6 +138,14 @@ public void equals() {
// resets modelManager to initial state for upcoming tests
modelManager.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ // different focusedPerson -> returns false
+ Person defaultPerson = modelManager.getFocusedPerson().get();
+ modelManager.getFocusedPerson().set(ALICE);
+ assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs)));
+
+ // resets modelManager to initial state for upcoming tests
+ modelManager.getFocusedPerson().set(defaultPerson);
+
// different userPrefs -> returns false
UserPrefs differentUserPrefs = new UserPrefs();
differentUserPrefs.setAddressBookFilePath(Paths.get("differentFilePath"));
diff --git a/src/test/java/seedu/address/model/UserPrefsTest.java b/src/test/java/bizbook/model/UserPrefsTest.java
similarity index 63%
rename from src/test/java/seedu/address/model/UserPrefsTest.java
rename to src/test/java/bizbook/model/UserPrefsTest.java
index b1307a70d52..a8d8520ac4a 100644
--- a/src/test/java/seedu/address/model/UserPrefsTest.java
+++ b/src/test/java/bizbook/model/UserPrefsTest.java
@@ -1,6 +1,6 @@
-package seedu.address.model;
+package bizbook.model;
-import static seedu.address.testutil.Assert.assertThrows;
+import static bizbook.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
@@ -18,4 +18,9 @@ public void setAddressBookFilePath_nullPath_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> userPrefs.setAddressBookFilePath(null));
}
+ @Test
+ public void setExportDirectoryPath_nullPath_throwsNullPointerException() {
+ UserPrefs userPrefs = new UserPrefs();
+ assertThrows(NullPointerException.class, () -> userPrefs.setExportDirectoryPath(null));
+ }
}
diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/bizbook/model/person/AddressTest.java
similarity index 94%
rename from src/test/java/seedu/address/model/person/AddressTest.java
rename to src/test/java/bizbook/model/person/AddressTest.java
index 314885eca26..b359548b4f4 100644
--- a/src/test/java/seedu/address/model/person/AddressTest.java
+++ b/src/test/java/bizbook/model/person/AddressTest.java
@@ -1,8 +1,8 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/bizbook/model/person/EmailTest.java
similarity index 97%
rename from src/test/java/seedu/address/model/person/EmailTest.java
rename to src/test/java/bizbook/model/person/EmailTest.java
index f08cdff0a64..c4e955d0144 100644
--- a/src/test/java/seedu/address/model/person/EmailTest.java
+++ b/src/test/java/bizbook/model/person/EmailTest.java
@@ -1,8 +1,8 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/bizbook/model/person/NameContainsKeywordsPredicateTest.java
similarity index 95%
rename from src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
rename to src/test/java/bizbook/model/person/NameContainsKeywordsPredicateTest.java
index 6b3fd90ade7..9c87b93f7df 100644
--- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
+++ b/src/test/java/bizbook/model/person/NameContainsKeywordsPredicateTest.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package bizbook.model.person;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -10,7 +10,7 @@
import org.junit.jupiter.api.Test;
-import seedu.address.testutil.PersonBuilder;
+import bizbook.testutil.PersonBuilder;
public class NameContainsKeywordsPredicateTest {
@@ -69,8 +69,8 @@ public void test_nameDoesNotContainKeywords_returnsFalse() {
assertFalse(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
// Keywords match phone, email and address, but does not match name
- predicate = new NameContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
+ predicate = new NameContainsKeywordsPredicate(Arrays.asList("81234567", "alice@email.com", "Main", "Street"));
+ assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("81234567")
.withEmail("alice@email.com").withAddress("Main Street").build()));
}
diff --git a/src/test/java/seedu/address/model/person/NameTest.java b/src/test/java/bizbook/model/person/NameTest.java
similarity index 95%
rename from src/test/java/seedu/address/model/person/NameTest.java
rename to src/test/java/bizbook/model/person/NameTest.java
index 94e3dd726bd..5da6d6ecf66 100644
--- a/src/test/java/seedu/address/model/person/NameTest.java
+++ b/src/test/java/bizbook/model/person/NameTest.java
@@ -1,8 +1,8 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/bizbook/model/person/NoteTest.java b/src/test/java/bizbook/model/person/NoteTest.java
new file mode 100644
index 00000000000..df204110bdc
--- /dev/null
+++ b/src/test/java/bizbook/model/person/NoteTest.java
@@ -0,0 +1,67 @@
+package bizbook.model.person;
+
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_HIGH_PROFILE_CLIENT;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_HIGH_PROFILE_CLIENT_LOWERCASE;
+import static bizbook.testutil.Assert.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class NoteTest {
+
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Note(null));
+ }
+
+ @Test
+ public void constructor_invalidEmail_throwsIllegalArgumentException() {
+ String invalidNote = "";
+ assertThrows(IllegalArgumentException.class, () -> new Note(invalidNote));
+ }
+
+ @Test
+ public void isValidNote() {
+ // null note
+ assertThrows(NullPointerException.class, () -> Note.isValidNoteName(null));
+
+ // blank note
+ assertFalse(Note.isValidNoteName("")); // empty string
+ assertFalse(Note.isValidNoteName(" ")); // spaces only
+
+ // invalid note - non-alphanumerical characters
+ assertFalse(Note.isValidNoteName("High profile_client")); // underscore in local part
+ assertFalse(Note.isValidNoteName("Likes.dumplings")); // period in local part
+ assertFalse(Note.isValidNoteName("Prefers handshakes+meetings")); // '+' symbol in local part
+ assertFalse(Note.isValidNoteName("High-importance")); // hyphen in local part
+
+ // valid note
+ assertTrue(Note.isValidNoteName("impt")); // minimal
+ assertTrue(Note.isValidNoteName("Likes dumplings")); // usual
+ assertTrue(Note.isValidNoteName("prefers handshakes and meetings")); // usual long
+ }
+
+ @Test
+ public void equals() {
+ Note note = new Note(VALID_NOTE_HIGH_PROFILE_CLIENT);
+
+ // same values -> returns true
+ assertTrue(note.equals(new Note(VALID_NOTE_HIGH_PROFILE_CLIENT)));
+
+ // same object -> returns true
+ assertTrue(note.equals(note));
+
+ // capitalised and non capitalised -> returns true
+ assertTrue(note.equals(new Note(VALID_NOTE_HIGH_PROFILE_CLIENT_LOWERCASE)));
+
+ // null -> returns false
+ assertFalse(note.equals(null));
+
+ // different types -> returns false
+ assertFalse(note.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(note.equals(new Note("other valid note")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/bizbook/model/person/PersonTest.java
similarity index 83%
rename from src/test/java/seedu/address/model/person/PersonTest.java
rename to src/test/java/bizbook/model/person/PersonTest.java
index 31a10d156c9..23bfd81dadf 100644
--- a/src/test/java/seedu/address/model/person/PersonTest.java
+++ b/src/test/java/bizbook/model/person/PersonTest.java
@@ -1,20 +1,20 @@
-package seedu.address.model.person;
-
+package bizbook.model.person;
+
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.ALICE;
+import static bizbook.testutil.TypicalPersons.BOB;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BOB;
import org.junit.jupiter.api.Test;
-import seedu.address.testutil.PersonBuilder;
+import bizbook.testutil.PersonBuilder;
public class PersonTest {
@@ -93,7 +93,8 @@ public void equals() {
@Test
public void toStringMethod() {
String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
- + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + "}";
+ + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags()
+ + ", notes=" + ALICE.getNotes() + "}";
assertEquals(expected, ALICE.toString());
}
}
diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/bizbook/model/person/PhoneTest.java
similarity index 71%
rename from src/test/java/seedu/address/model/person/PhoneTest.java
rename to src/test/java/bizbook/model/person/PhoneTest.java
index deaaa5ba190..a1967f60652 100644
--- a/src/test/java/seedu/address/model/person/PhoneTest.java
+++ b/src/test/java/bizbook/model/person/PhoneTest.java
@@ -1,8 +1,8 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
@@ -27,23 +27,27 @@ public void isValidPhone() {
// invalid phone numbers
assertFalse(Phone.isValidPhone("")); // empty string
assertFalse(Phone.isValidPhone(" ")); // spaces only
- assertFalse(Phone.isValidPhone("91")); // less than 3 numbers
+
+ // less than 8 numbers even though it starts with 9
+ assertFalse(Phone.isValidPhone("91"));
+ assertFalse(Phone.isValidPhone("9123456"));
+
assertFalse(Phone.isValidPhone("phone")); // non-numeric
assertFalse(Phone.isValidPhone("9011p041")); // alphabets within digits
assertFalse(Phone.isValidPhone("9312 1534")); // spaces within digits
+ assertFalse(Phone.isValidPhone("12345678")); // exactly 8 numbers but does not start with 6, 8 or 9
// valid phone numbers
- assertTrue(Phone.isValidPhone("911")); // exactly 3 numbers
+ assertTrue(Phone.isValidPhone("91415691"));
assertTrue(Phone.isValidPhone("93121534"));
- assertTrue(Phone.isValidPhone("124293842033123")); // long phone numbers
}
@Test
public void equals() {
- Phone phone = new Phone("999");
+ Phone phone = new Phone("91415691");
// same values -> returns true
- assertTrue(phone.equals(new Phone("999")));
+ assertTrue(phone.equals(new Phone("91415691")));
// same object -> returns true
assertTrue(phone.equals(phone));
@@ -52,9 +56,9 @@ public void equals() {
assertFalse(phone.equals(null));
// different types -> returns false
- assertFalse(phone.equals(5.0f));
+ assertFalse(phone.equals(8.0f));
// different values -> returns false
- assertFalse(phone.equals(new Phone("995")));
+ assertFalse(phone.equals(new Phone("91415693")));
}
}
diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/bizbook/model/person/UniquePersonListTest.java
similarity index 91%
rename from src/test/java/seedu/address/model/person/UniquePersonListTest.java
rename to src/test/java/bizbook/model/person/UniquePersonListTest.java
index 17ae501df08..6602f202f48 100644
--- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java
+++ b/src/test/java/bizbook/model/person/UniquePersonListTest.java
@@ -1,13 +1,13 @@
-package seedu.address.model.person;
+package bizbook.model.person;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.ALICE;
+import static bizbook.testutil.TypicalPersons.BOB;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BOB;
import java.util.Arrays;
import java.util.Collections;
@@ -15,9 +15,9 @@
import org.junit.jupiter.api.Test;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-import seedu.address.testutil.PersonBuilder;
+import bizbook.model.person.exceptions.DuplicatePersonException;
+import bizbook.model.person.exceptions.PersonNotFoundException;
+import bizbook.testutil.PersonBuilder;
public class UniquePersonListTest {
diff --git a/src/test/java/seedu/address/model/tag/TagTest.java b/src/test/java/bizbook/model/tag/TagTest.java
similarity index 86%
rename from src/test/java/seedu/address/model/tag/TagTest.java
rename to src/test/java/bizbook/model/tag/TagTest.java
index 64d07d79ee2..62dcfbca96e 100644
--- a/src/test/java/seedu/address/model/tag/TagTest.java
+++ b/src/test/java/bizbook/model/tag/TagTest.java
@@ -1,6 +1,6 @@
-package seedu.address.model.tag;
+package bizbook.model.tag;
-import static seedu.address.testutil.Assert.assertThrows;
+import static bizbook.testutil.Assert.assertThrows;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/bizbook/storage/JsonAdaptedPersonTest.java
similarity index 58%
rename from src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
rename to src/test/java/bizbook/storage/JsonAdaptedPersonTest.java
index 83b11331cdb..2104f405a75 100644
--- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
+++ b/src/test/java/bizbook/storage/JsonAdaptedPersonTest.java
@@ -1,9 +1,10 @@
-package seedu.address.storage;
+package bizbook.storage;
+import static bizbook.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.BENSON;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.BENSON;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.List;
@@ -11,11 +12,12 @@
import org.junit.jupiter.api.Test;
-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.Phone;
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
public class JsonAdaptedPersonTest {
private static final String INVALID_NAME = "R@chel";
@@ -23,6 +25,7 @@ public class JsonAdaptedPersonTest {
private static final String INVALID_ADDRESS = " ";
private static final String INVALID_EMAIL = "example.com";
private static final String INVALID_TAG = "#friend";
+ private static final String INVALID_NOTE = "#likes dumpings";
private static final String VALID_NAME = BENSON.getName().toString();
private static final String VALID_PHONE = BENSON.getPhone().toString();
@@ -31,24 +34,29 @@ public class JsonAdaptedPersonTest {
private static final List VALID_TAGS = BENSON.getTags().stream()
.map(JsonAdaptedTag::new)
.collect(Collectors.toList());
+ private static final List VALID_NOTES = BENSON.getNotes().stream()
+ .map(JsonAdaptedNote::new)
+ .collect(Collectors.toList());
@Test
public void toModelType_validPersonDetails_returnsPerson() throws Exception {
JsonAdaptedPerson person = new JsonAdaptedPerson(BENSON);
+ System.out.println(BENSON.equals(person.toModelType()));
assertEquals(BENSON, person.toModelType());
}
@Test
public void toModelType_invalidName_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS, VALID_NOTES);
String expectedMessage = Name.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullName_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ VALID_TAGS, VALID_NOTES);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -56,14 +64,15 @@ public void toModelType_nullName_throwsIllegalValueException() {
@Test
public void toModelType_invalidPhone_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS, VALID_NOTES);
String expectedMessage = Phone.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS,
+ VALID_TAGS, VALID_NOTES);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -71,14 +80,15 @@ public void toModelType_nullPhone_throwsIllegalValueException() {
@Test
public void toModelType_invalidEmail_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS, VALID_NOTES);
String expectedMessage = Email.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS,
+ VALID_TAGS, VALID_NOTES);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -86,14 +96,15 @@ public void toModelType_nullEmail_throwsIllegalValueException() {
@Test
public void toModelType_invalidAddress_throwsIllegalValueException() {
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS);
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS, VALID_NOTES);
String expectedMessage = Address.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS);
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null,
+ VALID_TAGS, VALID_NOTES);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@@ -103,7 +114,45 @@ public void toModelType_invalidTags_throwsIllegalValueException() {
List invalidTags = new ArrayList<>(VALID_TAGS);
invalidTags.add(new JsonAdaptedTag(INVALID_TAG));
JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags);
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags, VALID_NOTES);
+ assertThrows(IllegalValueException.class, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_validPersonWithoutTags_returnsPerson() throws Exception {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ new ArrayList<>(), VALID_NOTES);
+ Person modelPerson = person.toModelType();
+
+ // Person should still be created successfully, but with no tags
+ assertTrue(modelPerson.getTags().isEmpty());
+ assertEquals(VALID_NAME, modelPerson.getName().fullName);
+ }
+
+ @Test
+ public void toModelType_invalidNotes_throwsIllegalValueException() {
+ List invalidNotes = new ArrayList<>(VALID_NOTES);
+ invalidNotes.add(new JsonAdaptedNote(INVALID_NOTE));
+ JsonAdaptedPerson person =
+ new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS, invalidNotes);
+ assertThrows(IllegalValueException.class, person::toModelType);
+ }
+
+ @Test
+ public void toModelType_validPersonWithoutNotes_returnsPerson() throws Exception {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ VALID_TAGS, new ArrayList<>());
+ Person modelPerson = person.toModelType();
+
+ // Person should still be created successfully, but with no tags
+ assertTrue(modelPerson.getNotes().isEmpty());
+ assertEquals(VALID_NAME, modelPerson.getName().fullName);
+ }
+
+ @Test
+ public void toModelType_allNullFields_throwsIllegalValueException() {
+ JsonAdaptedPerson person = new JsonAdaptedPerson(null, null, null, null,
+ null, null);
assertThrows(IllegalValueException.class, person::toModelType);
}
diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/bizbook/storage/JsonAddressBookStorageTest.java
similarity index 89%
rename from src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
rename to src/test/java/bizbook/storage/JsonAddressBookStorageTest.java
index 4e5ce9200c8..ad86452f5b6 100644
--- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
+++ b/src/test/java/bizbook/storage/JsonAddressBookStorageTest.java
@@ -1,12 +1,12 @@
-package seedu.address.storage;
+package bizbook.storage;
+import static bizbook.testutil.Assert.assertThrows;
+import static bizbook.testutil.TypicalPersons.ALICE;
+import static bizbook.testutil.TypicalPersons.HOON;
+import static bizbook.testutil.TypicalPersons.IDA;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.HOON;
-import static seedu.address.testutil.TypicalPersons.IDA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import java.io.IOException;
import java.nio.file.Path;
@@ -15,9 +15,9 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.model.AddressBook;
+import bizbook.model.ReadOnlyAddressBook;
public class JsonAddressBookStorageTest {
private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonAddressBookStorageTest");
diff --git a/src/test/java/bizbook/storage/JsonSerializableAddressBookTest.java b/src/test/java/bizbook/storage/JsonSerializableAddressBookTest.java
new file mode 100644
index 00000000000..0687494cc79
--- /dev/null
+++ b/src/test/java/bizbook/storage/JsonSerializableAddressBookTest.java
@@ -0,0 +1,79 @@
+package bizbook.storage;
+
+import static bizbook.testutil.Assert.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import bizbook.commons.exceptions.IllegalValueException;
+import bizbook.commons.util.JsonUtil;
+import bizbook.model.AddressBook;
+import bizbook.testutil.TypicalPersons;
+
+public class JsonSerializableAddressBookTest {
+
+ private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableAddressBookTest");
+ private static final Path TYPICAL_PERSONS_FILE = TEST_DATA_FOLDER.resolve("typicalPersonsAddressBook.json");
+ private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json");
+ private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json");
+
+ private static final Path TYPICAL_PINNED_PERSONS_FILE =
+ TEST_DATA_FOLDER.resolve("typicalPinnedPersonsAddressBook.json");
+ private static final Path INVALID_PINNED_PERSON_FILE =
+ TEST_DATA_FOLDER.resolve("invalidPinnedPersonAddressBook.json");
+ private static final Path DUPLICATE_PINNED_PERSON_FILE =
+ TEST_DATA_FOLDER.resolve("duplicatePinnedPersonAddressBook.json");
+
+ @Test
+ public void toModelType_typicalPersonsFile_success() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE,
+ JsonSerializableAddressBook.class).get();
+ AddressBook addressBookFromFile = dataFromFile.toModelType();
+ AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook();
+ assertEquals(addressBookFromFile, typicalPersonsAddressBook);
+ }
+
+ @Test
+ public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE,
+ JsonSerializableAddressBook.class).get();
+ assertThrows(IllegalValueException.class, dataFromFile::toModelType);
+ }
+
+ @Test
+ public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE,
+ JsonSerializableAddressBook.class).get();
+ assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON,
+ dataFromFile::toModelType);
+ }
+
+ @Test
+ public void toModelType_typicalPinnedPersonsFile_success() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PINNED_PERSONS_FILE,
+ JsonSerializableAddressBook.class).get();
+ AddressBook addressBookFromFile = dataFromFile.toModelType();
+ AddressBook typicalPinnedPersonsAddressBook = TypicalPersons.getTypicalAddressBookWithPinned();
+ assertEquals(addressBookFromFile, typicalPinnedPersonsAddressBook);
+ }
+
+ @Test
+ public void toModelType_invalidPinnedPersonFile_throwsIllegalValueException() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PINNED_PERSON_FILE,
+ JsonSerializableAddressBook.class).get();
+ assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_UNKNOWN_PERSON,
+ dataFromFile::toModelType);
+ }
+
+ @Test
+ public void toModelType_duplicatePinnedPersons_throwsIllegalValueException() throws Exception {
+ JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PINNED_PERSON_FILE,
+ JsonSerializableAddressBook.class).get();
+ assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PIN_PERSON,
+ dataFromFile::toModelType);
+ }
+
+}
diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/bizbook/storage/JsonUserPrefsStorageTest.java
similarity index 94%
rename from src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
rename to src/test/java/bizbook/storage/JsonUserPrefsStorageTest.java
index ed0a413526a..90061a13424 100644
--- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
+++ b/src/test/java/bizbook/storage/JsonUserPrefsStorageTest.java
@@ -1,8 +1,8 @@
-package seedu.address.storage;
+package bizbook.storage;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static seedu.address.testutil.Assert.assertThrows;
import java.io.IOException;
import java.nio.file.Path;
@@ -12,9 +12,9 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.UserPrefs;
+import bizbook.commons.core.GuiSettings;
+import bizbook.commons.exceptions.DataLoadingException;
+import bizbook.model.UserPrefs;
public class JsonUserPrefsStorageTest {
diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/bizbook/storage/StorageManagerTest.java
similarity index 88%
rename from src/test/java/seedu/address/storage/StorageManagerTest.java
rename to src/test/java/bizbook/storage/StorageManagerTest.java
index 99a16548970..c7cc2ae8147 100644
--- a/src/test/java/seedu/address/storage/StorageManagerTest.java
+++ b/src/test/java/bizbook/storage/StorageManagerTest.java
@@ -1,8 +1,8 @@
-package seedu.address.storage;
+package bizbook.storage;
+import static bizbook.testutil.TypicalPersons.getTypicalAddressBook;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
import java.nio.file.Path;
@@ -10,10 +10,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.UserPrefs;
+import bizbook.commons.core.GuiSettings;
+import bizbook.model.AddressBook;
+import bizbook.model.ReadOnlyAddressBook;
+import bizbook.model.UserPrefs;
public class StorageManagerTest {
diff --git a/src/test/java/seedu/address/testutil/AddressBookBuilder.java b/src/test/java/bizbook/testutil/AddressBookBuilder.java
similarity index 86%
rename from src/test/java/seedu/address/testutil/AddressBookBuilder.java
rename to src/test/java/bizbook/testutil/AddressBookBuilder.java
index d53799fd110..46c97f0e1a2 100644
--- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java
+++ b/src/test/java/bizbook/testutil/AddressBookBuilder.java
@@ -1,7 +1,7 @@
-package seedu.address.testutil;
+package bizbook.testutil;
-import seedu.address.model.AddressBook;
-import seedu.address.model.person.Person;
+import bizbook.model.AddressBook;
+import bizbook.model.person.Person;
/**
* A utility class to help with building Addressbook objects.
diff --git a/src/test/java/seedu/address/testutil/Assert.java b/src/test/java/bizbook/testutil/Assert.java
similarity index 97%
rename from src/test/java/seedu/address/testutil/Assert.java
rename to src/test/java/bizbook/testutil/Assert.java
index 9863093bd6e..bb0f3a4d5d1 100644
--- a/src/test/java/seedu/address/testutil/Assert.java
+++ b/src/test/java/bizbook/testutil/Assert.java
@@ -1,4 +1,4 @@
-package seedu.address.testutil;
+package bizbook.testutil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.function.Executable;
diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/bizbook/testutil/EditPersonDescriptorBuilder.java
similarity index 74%
rename from src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
rename to src/test/java/bizbook/testutil/EditPersonDescriptorBuilder.java
index 4584bd5044e..903d2cdbe82 100644
--- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
+++ b/src/test/java/bizbook/testutil/EditPersonDescriptorBuilder.java
@@ -1,16 +1,18 @@
-package seedu.address.testutil;
+package bizbook.testutil;
+import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-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 bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
/**
* A utility class to help with building EditPersonDescriptor objects.
@@ -37,6 +39,7 @@ public EditPersonDescriptorBuilder(Person person) {
descriptor.setEmail(person.getEmail());
descriptor.setAddress(person.getAddress());
descriptor.setTags(person.getTags());
+ descriptor.setNotes(person.getNotes());
}
/**
@@ -81,6 +84,16 @@ public EditPersonDescriptorBuilder withTags(String... tags) {
return this;
}
+ /**
+ * Parses the {@code notes} into a {@code ArrayList} and set it to the {@code EditPersonDescriptor}
+ * that we are building.
+ */
+ public EditPersonDescriptorBuilder withNotes(String... notes) {
+ ArrayList noteSet = Stream.of(notes).map(Note::new).collect(Collectors.toCollection(ArrayList::new));
+ descriptor.setNotes(noteSet);
+ return this;
+ }
+
public EditPersonDescriptor build() {
return descriptor;
}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/bizbook/testutil/PersonBuilder.java
similarity index 71%
rename from src/test/java/seedu/address/testutil/PersonBuilder.java
rename to src/test/java/bizbook/testutil/PersonBuilder.java
index 6be381d39ba..3a1b4c7ec35 100644
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ b/src/test/java/bizbook/testutil/PersonBuilder.java
@@ -1,15 +1,17 @@
-package seedu.address.testutil;
+package bizbook.testutil;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.Set;
-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 seedu.address.model.util.SampleDataUtil;
+import bizbook.model.person.Address;
+import bizbook.model.person.Email;
+import bizbook.model.person.Name;
+import bizbook.model.person.Note;
+import bizbook.model.person.Person;
+import bizbook.model.person.Phone;
+import bizbook.model.tag.Tag;
+import bizbook.model.util.SampleDataUtil;
/**
* A utility class to help with building Person objects.
@@ -26,6 +28,7 @@ public class PersonBuilder {
private Email email;
private Address address;
private Set tags;
+ private ArrayList notes;
/**
* Creates a {@code PersonBuilder} with the default details.
@@ -35,7 +38,8 @@ public PersonBuilder() {
phone = new Phone(DEFAULT_PHONE);
email = new Email(DEFAULT_EMAIL);
address = new Address(DEFAULT_ADDRESS);
- tags = new HashSet<>();
+ tags = new LinkedHashSet<>();
+ notes = new ArrayList<>();
}
/**
@@ -46,7 +50,8 @@ public PersonBuilder(Person personToCopy) {
phone = personToCopy.getPhone();
email = personToCopy.getEmail();
address = personToCopy.getAddress();
- tags = new HashSet<>(personToCopy.getTags());
+ tags = new LinkedHashSet<>(personToCopy.getTags());
+ notes = personToCopy.getNotes();
}
/**
@@ -89,8 +94,17 @@ public PersonBuilder withEmail(String email) {
return this;
}
+ /**
+ * Sets the {@code Notes} of the {@code Person} that we are building.
+ */
+ public PersonBuilder withNotes(String ... notes) {
+ this.notes = SampleDataUtil.getNoteList(notes);
+ return this;
+ }
+
public Person build() {
- return new Person(name, phone, email, address, tags);
+ return new Person(name, phone, email, address, tags, notes);
}
+
}
diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/bizbook/testutil/PersonUtil.java
similarity index 78%
rename from src/test/java/seedu/address/testutil/PersonUtil.java
rename to src/test/java/bizbook/testutil/PersonUtil.java
index 90849945183..c537f20f63e 100644
--- a/src/test/java/seedu/address/testutil/PersonUtil.java
+++ b/src/test/java/bizbook/testutil/PersonUtil.java
@@ -1,17 +1,17 @@
-package seedu.address.testutil;
+package bizbook.testutil;
-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 bizbook.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static bizbook.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static bizbook.logic.parser.CliSyntax.PREFIX_NAME;
+import static bizbook.logic.parser.CliSyntax.PREFIX_PHONE;
+import static bizbook.logic.parser.CliSyntax.PREFIX_TAG;
import java.util.Set;
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Person;
-import seedu.address.model.tag.Tag;
+import bizbook.logic.commands.AddCommand;
+import bizbook.logic.commands.EditCommand.EditPersonDescriptor;
+import bizbook.model.person.Person;
+import bizbook.model.tag.Tag;
/**
* A utility class for Person.
@@ -37,6 +37,7 @@ public static String getPersonDetails(Person person) {
person.getTags().stream().forEach(
s -> sb.append(PREFIX_TAG + s.tagName + " ")
);
+
return sb.toString();
}
diff --git a/src/test/java/seedu/address/testutil/SerializableTestClass.java b/src/test/java/bizbook/testutil/SerializableTestClass.java
similarity index 98%
rename from src/test/java/seedu/address/testutil/SerializableTestClass.java
rename to src/test/java/bizbook/testutil/SerializableTestClass.java
index f5a66340489..23200ae2503 100644
--- a/src/test/java/seedu/address/testutil/SerializableTestClass.java
+++ b/src/test/java/bizbook/testutil/SerializableTestClass.java
@@ -1,4 +1,4 @@
-package seedu.address.testutil;
+package bizbook.testutil;
import java.time.LocalDateTime;
import java.util.ArrayList;
diff --git a/src/test/java/bizbook/testutil/TestUtil.java b/src/test/java/bizbook/testutil/TestUtil.java
new file mode 100644
index 00000000000..0ec2230d563
--- /dev/null
+++ b/src/test/java/bizbook/testutil/TestUtil.java
@@ -0,0 +1,99 @@
+package bizbook.testutil;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import bizbook.commons.core.index.Index;
+import bizbook.commons.util.FileUtil;
+import bizbook.model.Model;
+import bizbook.model.person.Person;
+
+
+/**
+ * A utility class for test cases.
+ */
+public class TestUtil {
+
+ /**
+ * Folder used for temp files created during testing. Ignored by Git.
+ */
+ private static final Path SANDBOX_FOLDER = Paths.get("src", "test", "data", "sandbox");
+
+ /**
+ * Appends {@code fileName} to the sandbox folder path and returns the resulting path.
+ * Creates the sandbox folder if it doesn't exist.
+ */
+ public static Path getFilePathInSandboxFolder(String fileName) {
+ try {
+ Files.createDirectories(SANDBOX_FOLDER);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return SANDBOX_FOLDER.resolve(fileName);
+ }
+
+ /**
+ * Returns the middle index of the person in the {@code model}'s person list.
+ */
+ public static Index getMidIndex(Model model) {
+ return Index.fromOneBased(model.getFilteredPersonList().size() / 2);
+ }
+
+ /**
+ * Returns the last index of the person in the {@code model}'s person list.
+ */
+ public static Index getLastIndex(Model model) {
+ return Index.fromOneBased(model.getFilteredPersonList().size());
+ }
+
+ /**
+ * Returns the person in the {@code model}'s person list at {@code index}.
+ */
+ public static Person getPerson(Model model, Index index) {
+ return model.getFilteredPersonList().get(index.getZeroBased());
+ }
+
+ /**
+ * Returns the {@link Path} to the resource in the class' package.
+ * For example, for a class {@code X} in package {@code a.b.c},
+ * {@code getResourceFilePath(X.class, "subDir/myFile.txt");} will return the
+ * path to the file {@code resources/a/b/c/subDir/myFile.txt}
+ *
+ * @param klass the relative class to retrieve the resource from
+ * @param filePath the path to the file to retrieve
+ * @return path to the file
+ */
+ public static Path getResourceFilePath(Class> klass, String filePath) {
+ try {
+ URL url = klass.getResource(filePath);
+ assertNotNull(url, filePath + " does not exist.");
+ return Path.of(url.toURI());
+ } catch (URISyntaxException e) {
+ fail("Failed to get URI for resource: " + filePath);
+ throw new AssertionError("Failed to get URI for resource");
+ }
+ }
+
+ /**
+ * Returns the contents of the resource file in the class' package.
+ * For example, for a class {@code X} in package {@code a.b.c},
+ * {@code readResourceFile(X.class, "subDir/myFile.txt");} will return the
+ * contents in the file {@code resources/a/b/c/subDir/myFile.txt}
+ *
+ * @param klass the relative class to retrieve the resource from
+ * @param filePath the path to the file to retrieve
+ * @return contents of the resource file
+ * @throws IOException when reading the file fails
+ */
+ public static String readResourceFile(Class> klass, String filePath) throws IOException {
+ Path path = getResourceFilePath(klass, filePath);
+ return FileUtil.readFromFile(path);
+ }
+}
diff --git a/src/test/java/bizbook/testutil/TypicalFileTypes.java b/src/test/java/bizbook/testutil/TypicalFileTypes.java
new file mode 100644
index 00000000000..6b890c55a4a
--- /dev/null
+++ b/src/test/java/bizbook/testutil/TypicalFileTypes.java
@@ -0,0 +1,11 @@
+package bizbook.testutil;
+
+import bizbook.logic.commands.exporter.FileType;
+
+/**
+ * A utility class containing a list of valid file types to be used in tests.
+ */
+public class TypicalFileTypes {
+ public static final FileType FILE_TYPE_CSV = FileType.CSV;
+ public static final FileType FILE_TYPE_VCF = FileType.VCF;
+}
diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/bizbook/testutil/TypicalIndexes.java
similarity index 53%
rename from src/test/java/seedu/address/testutil/TypicalIndexes.java
rename to src/test/java/bizbook/testutil/TypicalIndexes.java
index 1e613937657..de7b5f499b8 100644
--- a/src/test/java/seedu/address/testutil/TypicalIndexes.java
+++ b/src/test/java/bizbook/testutil/TypicalIndexes.java
@@ -1,6 +1,6 @@
-package seedu.address.testutil;
+package bizbook.testutil;
-import seedu.address.commons.core.index.Index;
+import bizbook.commons.core.index.Index;
/**
* A utility class containing a list of {@code Index} objects to be used in tests.
@@ -9,4 +9,8 @@ public class TypicalIndexes {
public static final Index INDEX_FIRST_PERSON = Index.fromOneBased(1);
public static final Index INDEX_SECOND_PERSON = Index.fromOneBased(2);
public static final Index INDEX_THIRD_PERSON = Index.fromOneBased(3);
+ public static final Index INDEX_OUTOFBOUND_PERSON = Index.fromOneBased(1000);
+
+ public static final Index INDEX_FIRST_NOTE = Index.fromOneBased(1);
+ public static final Index INDEX_OUTOFBOUND_NOTE = Index.fromOneBased(1000);
}
diff --git a/src/test/java/bizbook/testutil/TypicalNotes.java b/src/test/java/bizbook/testutil/TypicalNotes.java
new file mode 100644
index 00000000000..2f88d4bdfca
--- /dev/null
+++ b/src/test/java/bizbook/testutil/TypicalNotes.java
@@ -0,0 +1,13 @@
+package bizbook.testutil;
+
+import bizbook.model.person.Note;
+
+/**
+ * A utility class containing a list of {@code Notes} objects to be used in tests.
+ */
+public class TypicalNotes {
+ public static final Note TYPICAL_NOTE = new Note("Loves Ramen");
+ public static final Note DUPLICATE_NOTE = new Note("Likes dumplings");
+
+ public static final Note VALID_NOTE = new Note("Best Customer");
+}
diff --git a/src/test/java/bizbook/testutil/TypicalPersons.java b/src/test/java/bizbook/testutil/TypicalPersons.java
new file mode 100644
index 00000000000..1db60734e05
--- /dev/null
+++ b/src/test/java/bizbook/testutil/TypicalPersons.java
@@ -0,0 +1,105 @@
+package bizbook.testutil;
+
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_ADDRESS_CHARLIE;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_EMAIL_CHARLIE;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NAME_CHARLIE;
+import static bizbook.logic.commands.CommandTestUtil.VALID_NOTE_LIKES_CATS;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static bizbook.logic.commands.CommandTestUtil.VALID_PHONE_CHARLIE;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
+import static bizbook.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import bizbook.model.AddressBook;
+import bizbook.model.person.Person;
+
+/**
+ * A utility class containing a list of {@code Person} objects to be used in tests.
+ */
+public class TypicalPersons {
+
+ public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
+ .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
+ .withPhone("94351253")
+ .withTags("friends")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
+ .withAddress("311, Clementi Ave 2, #02-25")
+ .withEmail("johnd@example.com").withPhone("98765432")
+ .withTags("owesMoney", "friends")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
+ .withEmail("heinz@example.com").withAddress("wall street")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
+ .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("94822245")
+ .withEmail("werner@example.com").withAddress("michegan ave")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("94824275")
+ .withEmail("lydia@example.com").withAddress("little tokyo")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("94824423")
+ .withEmail("anna@example.com").withAddress("4th street")
+ .withNotes("High profile client", "Likes dumplings").build();
+
+ // Manually added
+ public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("84824245")
+ .withEmail("stefan@example.com").withAddress("little india")
+ .withNotes("High profile client", "Likes dumplings").build();
+ public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("84821314")
+ .withEmail("hans@example.com").withAddress("chicago ave")
+ .withNotes("High profile client", "Likes dumplings").build();
+
+ // Manually added - Person's details found in {@code CommandTestUtil}
+ public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
+ .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
+ public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
+ .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
+ .build();
+ public static final Person CHARLIE = new PersonBuilder().withName(VALID_NAME_CHARLIE).withPhone(VALID_PHONE_CHARLIE)
+ .withEmail(VALID_EMAIL_CHARLIE).withAddress(VALID_ADDRESS_CHARLIE).withTags(VALID_TAG_FRIEND)
+ .withNotes(VALID_NOTE_LIKES_CATS).build();
+
+ public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
+
+ private TypicalPersons() {} // prevents instantiation
+
+ /**
+ * Returns an {@code AddressBook} with all the typical persons.
+ */
+ public static AddressBook getTypicalAddressBook() {
+ AddressBook ab = new AddressBook();
+ for (Person person : getTypicalPersons()) {
+ ab.addPerson(person);
+ }
+ return ab;
+ }
+
+ /**
+ * Returns an {@code AddressBook} with all the typical persons and a pinned person.
+ */
+ public static AddressBook getTypicalAddressBookWithPinned() {
+ AddressBook ab = new AddressBook();
+ for (Person person : getTypicalPersons()) {
+ ab.addPerson(person);
+ }
+ ab.addPinnedPerson(ALICE);
+ return ab;
+ }
+
+ public static List getTypicalPersons() {
+ return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
+ }
+}
diff --git a/src/test/java/seedu/address/ui/TestFxmlObject.java b/src/test/java/bizbook/ui/TestFxmlObject.java
similarity index 97%
rename from src/test/java/seedu/address/ui/TestFxmlObject.java
rename to src/test/java/bizbook/ui/TestFxmlObject.java
index 93f40f1276a..7f154ccfd50 100644
--- a/src/test/java/seedu/address/ui/TestFxmlObject.java
+++ b/src/test/java/bizbook/ui/TestFxmlObject.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package bizbook.ui;
import java.util.Objects;
diff --git a/src/test/java/seedu/address/ui/UiPartTest.java b/src/test/java/bizbook/ui/UiPartTest.java
similarity index 97%
rename from src/test/java/seedu/address/ui/UiPartTest.java
rename to src/test/java/bizbook/ui/UiPartTest.java
index 33d82d911b8..57bf355c9bf 100644
--- a/src/test/java/seedu/address/ui/UiPartTest.java
+++ b/src/test/java/bizbook/ui/UiPartTest.java
@@ -1,8 +1,8 @@
-package seedu.address.ui;
+package bizbook.ui;
+import static bizbook.testutil.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static seedu.address.testutil.Assert.assertThrows;
import java.net.URL;
import java.nio.file.Path;
@@ -10,8 +10,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import bizbook.MainApp;
import javafx.fxml.FXML;
-import seedu.address.MainApp;
public class UiPartTest {
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
deleted file mode 100644
index 5a1ab3dbc0c..00000000000
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package seedu.address.logic.parser;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-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;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
-import seedu.address.testutil.PersonUtil;
-
-public class AddressBookParserTest {
-
- private final AddressBookParser parser = new AddressBookParser();
-
- @Test
- public void parseCommand_add() throws Exception {
- Person person = new PersonBuilder().build();
- AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person));
- assertEquals(new AddCommand(person), command);
- }
-
- @Test
- public void parseCommand_clear() throws Exception {
- assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand);
- assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand);
- }
-
- @Test
- public void parseCommand_delete() throws Exception {
- DeleteCommand command = (DeleteCommand) parser.parseCommand(
- DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
- assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
- }
-
- @Test
- public void parseCommand_edit() throws Exception {
- Person person = new PersonBuilder().build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
- EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
- + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
- assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
- }
-
- @Test
- public void parseCommand_exit() throws Exception {
- assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand);
- assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand);
- }
-
- @Test
- public void parseCommand_find() throws Exception {
- List keywords = Arrays.asList("foo", "bar", "baz");
- FindCommand command = (FindCommand) parser.parseCommand(
- FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
- assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
- }
-
- @Test
- public void parseCommand_help() throws Exception {
- assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
- assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand);
- }
-
- @Test
- public void parseCommand_list() throws Exception {
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
- }
-
- @Test
- public void parseCommand_unrecognisedInput_throwsParseException() {
- assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
- -> parser.parseCommand(""));
- }
-
- @Test
- public void parseCommand_unknownCommand_throwsParseException() {
- assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
- }
-}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
deleted file mode 100644
index 6a40e14a649..00000000000
--- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
-import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.logic.commands.DeleteCommand;
-
-/**
- * As we are only doing white-box testing, our test cases do not cover path variations
- * outside of the DeleteCommand code. For example, inputs "1" and "1 abc" take the
- * same path through the DeleteCommand, and therefore we test only one of them.
- * The path variation for those two cases occur inside the ParserUtil, and
- * therefore should be covered by the ParserUtilTest.
- */
-public class DeleteCommandParserTest {
-
- private DeleteCommandParser parser = new DeleteCommandParser();
-
- @Test
- public void parse_validArgs_returnsDeleteCommand() {
- assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
- }
-
- @Test
- public void parse_invalidArgs_throwsParseException() {
- assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
- }
-}
diff --git a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
deleted file mode 100644
index 188c9058d20..00000000000
--- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package seedu.address.storage;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.AddressBook;
-import seedu.address.testutil.TypicalPersons;
-
-public class JsonSerializableAddressBookTest {
-
- private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableAddressBookTest");
- private static final Path TYPICAL_PERSONS_FILE = TEST_DATA_FOLDER.resolve("typicalPersonsAddressBook.json");
- private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json");
- private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json");
-
- @Test
- public void toModelType_typicalPersonsFile_success() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE,
- JsonSerializableAddressBook.class).get();
- AddressBook addressBookFromFile = dataFromFile.toModelType();
- AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook();
- assertEquals(addressBookFromFile, typicalPersonsAddressBook);
- }
-
- @Test
- public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE,
- JsonSerializableAddressBook.class).get();
- assertThrows(IllegalValueException.class, dataFromFile::toModelType);
- }
-
- @Test
- public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE,
- JsonSerializableAddressBook.class).get();
- assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON,
- dataFromFile::toModelType);
- }
-
-}
diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/address/testutil/TestUtil.java
deleted file mode 100644
index 896d103eb0b..00000000000
--- a/src/test/java/seedu/address/testutil/TestUtil.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package seedu.address.testutil;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * A utility class for test cases.
- */
-public class TestUtil {
-
- /**
- * Folder used for temp files created during testing. Ignored by Git.
- */
- private static final Path SANDBOX_FOLDER = Paths.get("src", "test", "data", "sandbox");
-
- /**
- * Appends {@code fileName} to the sandbox folder path and returns the resulting path.
- * Creates the sandbox folder if it doesn't exist.
- */
- public static Path getFilePathInSandboxFolder(String fileName) {
- try {
- Files.createDirectories(SANDBOX_FOLDER);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return SANDBOX_FOLDER.resolve(fileName);
- }
-
- /**
- * Returns the middle index of the person in the {@code model}'s person list.
- */
- public static Index getMidIndex(Model model) {
- return Index.fromOneBased(model.getFilteredPersonList().size() / 2);
- }
-
- /**
- * Returns the last index of the person in the {@code model}'s person list.
- */
- public static Index getLastIndex(Model model) {
- return Index.fromOneBased(model.getFilteredPersonList().size());
- }
-
- /**
- * Returns the person in the {@code model}'s person list at {@code index}.
- */
- public static Person getPerson(Model model, Index index) {
- return model.getFilteredPersonList().get(index.getZeroBased());
- }
-}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
deleted file mode 100644
index fec76fb7129..00000000000
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package seedu.address.testutil;
-
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * A utility class containing a list of {@code Person} objects to be used in tests.
- */
-public class TypicalPersons {
-
- public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
- .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
- .withPhone("94351253")
- .withTags("friends").build();
- public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
- .withAddress("311, Clementi Ave 2, #02-25")
- .withEmail("johnd@example.com").withPhone("98765432")
- .withTags("owesMoney", "friends").build();
- public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
- .withEmail("heinz@example.com").withAddress("wall street").build();
- public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
- .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build();
- public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
- .withEmail("werner@example.com").withAddress("michegan ave").build();
- public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
- .withEmail("lydia@example.com").withAddress("little tokyo").build();
- public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
- .withEmail("anna@example.com").withAddress("4th street").build();
-
- // Manually added
- public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
- .withEmail("stefan@example.com").withAddress("little india").build();
- public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("8482131")
- .withEmail("hans@example.com").withAddress("chicago ave").build();
-
- // Manually added - Person's details found in {@code CommandTestUtil}
- public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
- .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
- public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
- .build();
-
- public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
-
- private TypicalPersons() {} // prevents instantiation
-
- /**
- * Returns an {@code AddressBook} with all the typical persons.
- */
- public static AddressBook getTypicalAddressBook() {
- AddressBook ab = new AddressBook();
- for (Person person : getTypicalPersons()) {
- ab.addPerson(person);
- }
- return ab;
- }
-
- public static List getTypicalPersons() {
- return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
- }
-}
diff --git a/src/test/resources/bizbook/logic/commands/ImportCommandTest/invalid_info.vcf b/src/test/resources/bizbook/logic/commands/ImportCommandTest/invalid_info.vcf
new file mode 100644
index 00000000000..a089bfbe92a
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/ImportCommandTest/invalid_info.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Charlie Dee1
+N:;Charlie Dee1
+TEL:71111111
+EMAIL:charlie@example.com^
+ADR:;;Block 987\, Charlie Street 2@
+CATEGORIES:friend
+NOTE:likes cats@
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/ImportCommandTest/typical.vcf b/src/test/resources/bizbook/logic/commands/ImportCommandTest/typical.vcf
new file mode 100644
index 00000000000..254579c08f8
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/ImportCommandTest/typical.vcf
@@ -0,0 +1,80 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Alice Pauline
+N:;Alice Pauline
+TEL:94351253
+EMAIL:alice@example.com
+ADR:;;123\, Jurong West Ave 6\, #08-111
+CATEGORIES:friends
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Benson Meier
+N:;Benson Meier
+TEL:98765432
+EMAIL:johnd@example.com
+ADR:;;311\, Clementi Ave 2\, #02-25
+CATEGORIES:owesMoney,friends
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Carl Kurz
+N:;Carl Kurz
+TEL:95352563
+EMAIL:heinz@example.com
+ADR:;;wall street
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Daniel Meier
+N:;Daniel Meier
+TEL:87652533
+EMAIL:cornelia@example.com
+ADR:;;10th street
+CATEGORIES:friends
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Elle Meyer
+N:;Elle Meyer
+TEL:94822245
+EMAIL:werner@example.com
+ADR:;;michegan ave
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Fiona Kunz
+N:;Fiona Kunz
+TEL:94824275
+EMAIL:lydia@example.com
+ADR:;;little tokyo
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:George Best
+N:;George Best
+TEL:94824423
+EMAIL:anna@example.com
+ADR:;;4th street
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/CsvExporterTest/charlie.csv b/src/test/resources/bizbook/logic/commands/exporter/CsvExporterTest/charlie.csv
new file mode 100644
index 00000000000..08c46ea3eb2
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/CsvExporterTest/charlie.csv
@@ -0,0 +1,2 @@
+Name,Phone No,Email,Address,Tags,Notes
+Charlie Dee,81111111,charlie@example.com,"Block 987, Charlie Street 2","friend","likes cats"
diff --git a/src/test/resources/bizbook/logic/commands/exporter/CsvExporterTest/people.csv b/src/test/resources/bizbook/logic/commands/exporter/CsvExporterTest/people.csv
new file mode 100644
index 00000000000..472665082a3
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/CsvExporterTest/people.csv
@@ -0,0 +1,4 @@
+Name,Phone No,Email,Address,Tags,Notes
+Amy Bee,91111111,amy@example.com,"Block 312, Amy Street 1","friend",""
+Bob Choo,62222222,bob@example.com,"Block 123, Bobby Street 3","friend,husband",""
+Charlie Dee,81111111,charlie@example.com,"Block 987, Charlie Street 2","friend","likes cats"
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfExporterTest/charlie.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfExporterTest/charlie.vcf
new file mode 100644
index 00000000000..fc99e71d2b8
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfExporterTest/charlie.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Charlie Dee
+N:;Charlie Dee
+TEL:81111111
+EMAIL:charlie@example.com
+ADR:;;Block 987\, Charlie Street 2
+CATEGORIES:friend
+NOTE:likes cats
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfExporterTest/people.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfExporterTest/people.vcf
new file mode 100644
index 00000000000..5212f4f053b
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfExporterTest/people.vcf
@@ -0,0 +1,31 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Amy Bee
+N:;Amy Bee
+TEL:91111111
+EMAIL:amy@example.com
+ADR:;;Block 312\, Amy Street 1
+CATEGORIES:friend
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Bob Choo
+N:;Bob Choo
+TEL:62222222
+EMAIL:bob@example.com
+ADR:;;Block 123\, Bobby Street 3
+CATEGORIES:friend,husband
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Charlie Dee
+N:;Charlie Dee
+TEL:81111111
+EMAIL:charlie@example.com
+ADR:;;Block 987\, Charlie Street 2
+CATEGORIES:friend
+NOTE:likes cats
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/empty.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/empty.vcf
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/invalid_info.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/invalid_info.vcf
new file mode 100644
index 00000000000..a089bfbe92a
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/invalid_info.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Charlie Dee1
+N:;Charlie Dee1
+TEL:71111111
+EMAIL:charlie@example.com^
+ADR:;;Block 987\, Charlie Street 2@
+CATEGORIES:friend
+NOTE:likes cats@
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/missing_info.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/missing_info.vcf
new file mode 100644
index 00000000000..26bc575d583
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/missing_info.vcf
@@ -0,0 +1,10 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Charlie Dee
+N:;Charlie Dee
+TEL:81111111
+EMAIL:charlie@example.com
+CATEGORIES:friend
+NOTE:likes cats
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/single.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/single.vcf
new file mode 100644
index 00000000000..fc99e71d2b8
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/single.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Charlie Dee
+N:;Charlie Dee
+TEL:81111111
+EMAIL:charlie@example.com
+ADR:;;Block 987\, Charlie Street 2
+CATEGORIES:friend
+NOTE:likes cats
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/typical.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/typical.vcf
new file mode 100644
index 00000000000..254579c08f8
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/typical.vcf
@@ -0,0 +1,80 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Alice Pauline
+N:;Alice Pauline
+TEL:94351253
+EMAIL:alice@example.com
+ADR:;;123\, Jurong West Ave 6\, #08-111
+CATEGORIES:friends
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Benson Meier
+N:;Benson Meier
+TEL:98765432
+EMAIL:johnd@example.com
+ADR:;;311\, Clementi Ave 2\, #02-25
+CATEGORIES:owesMoney,friends
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Carl Kurz
+N:;Carl Kurz
+TEL:95352563
+EMAIL:heinz@example.com
+ADR:;;wall street
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Daniel Meier
+N:;Daniel Meier
+TEL:87652533
+EMAIL:cornelia@example.com
+ADR:;;10th street
+CATEGORIES:friends
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Elle Meyer
+N:;Elle Meyer
+TEL:94822245
+EMAIL:werner@example.com
+ADR:;;michegan ave
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:Fiona Kunz
+N:;Fiona Kunz
+TEL:94824275
+EMAIL:lydia@example.com
+ADR:;;little tokyo
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
+BEGIN:VCARD
+VERSION:3.0
+PRODID:ez-vcard 0.12.1
+FN:George Best
+N:;George Best
+TEL:94824423
+EMAIL:anna@example.com
+ADR:;;4th street
+NOTE:High profile client
+NOTE:Likes dumplings
+END:VCARD
diff --git a/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/wrong_format.vcf b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/wrong_format.vcf
new file mode 100644
index 00000000000..7ecdbb2814b
--- /dev/null
+++ b/src/test/resources/bizbook/logic/commands/exporter/VcfImporterTest/wrong_format.vcf
@@ -0,0 +1,6 @@
+END:END
+BEGIN:VCARD
+FN:Charlie Dee
+TEL:81111111
+EMAIL:charlie@example.com
+ADR:;;
diff --git a/src/test/resources/view/UiPartTest/validFile.fxml b/src/test/resources/view/UiPartTest/validFile.fxml
index bab836af0db..ad32e1d8ac2 100644
--- a/src/test/resources/view/UiPartTest/validFile.fxml
+++ b/src/test/resources/view/UiPartTest/validFile.fxml
@@ -1,4 +1,4 @@
-
+
Hello World!
diff --git a/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml b/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml
index 1a8b2c9e4d3..c49dcfb0ce9 100644
--- a/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml
+++ b/src/test/resources/view/UiPartTest/validFileWithFxRoot.fxml
@@ -1,6 +1,6 @@
-
+Hello World!