diff --git a/.classpath b/.classpath index 3f05f311a90b..c999801076cc 100644 --- a/.classpath +++ b/.classpath @@ -15,7 +15,7 @@ - + diff --git a/.project b/.project index 1c9339c5f927..f07b7c798f6e 100644 --- a/.project +++ b/.project @@ -1,7 +1,7 @@ - addressbook-level4 - Project addressbook-level4 created by Buildship. + main-final + Project main-final created by Buildship. @@ -20,4 +20,24 @@ org.eclipse.buildship.core.gradleprojectnature org.eclipse.jdt.core.javanature + + + 1478618700355 + + 26 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-build + + + + 1478618700593 + + 26 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-.gradle + + + diff --git a/.settings/gradle.prefs b/.settings/gradle.prefs new file mode 100644 index 000000000000..2840164a4657 --- /dev/null +++ b/.settings/gradle.prefs @@ -0,0 +1,12 @@ +{ + "1.0": { + "project_path": ":", + "project_dir": "/Users/ravi/Desktop/main", + "connection_project_dir": "/Users/ravi/Desktop/main", + "connection_gradle_user_home": null, + "connection_gradle_distribution": "GRADLE_DISTRIBUTION(WRAPPER)", + "connection_java_home": null, + "connection_jvm_arguments": "", + "connection_arguments": "" + } +} \ No newline at end of file diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs index 4e0fc71ac89f..a34e7665afa0 100644 --- a/.settings/org.eclipse.buildship.core.prefs +++ b/.settings/org.eclipse.buildship.core.prefs @@ -1,3 +1,6 @@ +GRADLE_BUILD_COMMANDS=org.eclipse.jdt.core.javabuilder +GRADLE_FILTERS=1.0-projectRelativePath-matches-false-false-build,1.0-projectRelativePath-matches-false-false-.gradle +GRADLE_NATURES=org.eclipse.jdt.core.javanature build.commands=org.eclipse.jdt.core.javabuilder connection.arguments= connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) diff --git a/.travis.yml b/.travis.yml index a9d9e9b47d87..2fb15bd6ef0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,4 +10,4 @@ before_install: addons: apt: packages: - - oracle-java8-installer + - oracle-java8-installer diff --git a/Collate-GUI.jar b/Collate-GUI.jar new file mode 100644 index 000000000000..3f9e6de8069c Binary files /dev/null and b/Collate-GUI.jar differ diff --git a/README.md b/README.md index 249a00b3899c..f2b87a75bc0d 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,13 @@ [![Build Status](https://travis-ci.org/se-edu/addressbook-level4.svg?branch=master)](https://travis-ci.org/se-edu/addressbook-level4) -[![Coverage Status](https://coveralls.io/repos/github/se-edu/addressbook-level4/badge.svg?branch=master)](https://coveralls.io/github/se-edu/addressbook-level4?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/CS2103AUG2016-F10-C3/main/badge.svg?branch=master)](https://coveralls.io/github/CS2103AUG2016-F10-C3/main?branch=master) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/72e712e19dd241cfa8820139dbab0bef)](https://www.codacy.com/app/shwetha-ravi3/main?utm_source=github.com&utm_medium=referral&utm_content=CS2103AUG2016-F10-C3/main&utm_campaign=Badge_Grade) -# Address Book (Level 4) +# Tary -
+
-* This is a desktop Address Book application. It has a GUI but most of the user interactions happen using +* This is a desktop GTD (Get things done) application. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface). -* It is a Java sample application intended for students learning Software Engineering while using Java as - the main programming language. -* It is **written in OOP fashion**. It provides a **reasonably well-written** code example that is - **significantly bigger** (around 6 KLoC)than what students usually write in beginner-level SE modules. -* What's different from [level 3](https://github.com/se-edu/addressbook-level3): - * A more sophisticated GUI that includes a list panel and an in-built Browser. - * More test cases, including automated GUI testing. - * Support for *Build Automation* using Gradle and for *Continuous Integration* using Travis CI. - #### Site Map * [User Guide](docs/UserGuide.md) diff --git a/build.gradle b/build.gradle index 46b06c1e42ec..d919b55ed8de 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,7 @@ allprojects { compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonDataTypeVersion" compile "com.google.guava:guava:$guavaVersion" + compile "com.joestelmach:natty:0.7" testCompile "junit:junit:$junitVersion" testCompile "org.testfx:testfx-core:$testFxVersion" @@ -74,10 +75,10 @@ allprojects { } shadowJar { - archiveName = "addressbook.jar" + archiveName = "tary.jar" manifest { - attributes "Main-Class": "seedu.address.MainApp" + attributes "Main-Class": "seedu.gtd.MainApp" } destinationDir = file("${buildDir}/jar/") @@ -138,7 +139,7 @@ task guiTests(type: AddressBookTest) { task nonGuiTests(type: AddressBookTest) { - include 'seedu/address/**' + include 'seedu/gtd/**' jacoco { destinationFile = new File("${buildDir}/jacoco/test.exec") diff --git a/collated/docs/A0130677A.md b/collated/docs/A0130677A.md new file mode 100644 index 000000000000..d0de4c459d1d --- /dev/null +++ b/collated/docs/A0130677A.md @@ -0,0 +1,148 @@ +# A0130677A +###### /UserGuide.md +``` md + +### Adding a person: `add` +**Format:** `add NAME [a/LOCATION s/START_DATE d/DEADLINE_OR_END_DATE p/PRIORITY t/TAGS]`
+* Adds a task to the task list in a flexible format (in any order). +* All parameters except name are optional. +* This command supports 3 types of tasks: floating tasks, event tasks and deadline tasks. +* Persons can have any number of tags (including 0) +
+Examples: +* Floating task: `add Visit Dentist` +* Event task: `add hackathon a/NUS s/tomorrow d/sunday p/3 t/preparation` +* Deadline task: `add submit tutorial d/monday p/5` + +**Field Type Constraints** +* Task duedate or startdate is formatted like the following: Wed Nov 02 15:39:55 UTC 2016 +* Accepted formal dates: 1978-01-28, 1984/04/02, 1/02/1980, 2/28/79 +* Relaxed dates: The 31st of April in the year 2008, Fri, 21 Nov 1997, Jan 21, '97, Sun, Nov 21, jan 1st, february twenty-eighth +* Relative dates: next thursday, last wednesday, today, tomorrow, yesterday, next week, next month, next year, 3 days from * now, three weeks ago +* Prefixes: day after, the day before, the monday after, the monday before, 2 fridays before, 4 tuesdays after +* Time: 0600h, 06:00 hours, 6pm, 5:30 a.m., 5, 12:59, 23:59, 8p, noon, afternoon, midnight +* Relative times: 10 seconds ago, in 5 minutes, 4 minutes from now. +


+ +### Mark task as done : `done` +Format: `done INDEX` +Marks a task as done by the index displayed on the task panel.
+* tasks marked as done can be shown when using command 'list done' +* once marked as done, cannot be undone unless using `undone` command immediately +


+ +### Edit task by attributes: `edit` +Format: `edit INDEX [NEW_NAME] FIELD_TYPE/NEW_FIELD_DETAILS` +Edits a task as done by the index displayed on the task panel.
+* to change the name only, use `edit NEW_NAME` without specifying field type +* able to accept multiple field types e.g. `edit 2 taskA a/NUS d/friday` +


+ +### Undo previous command: `undo` +Format: `undo` +Undo the last command.
+* multiple undos supported. +


+ +### Listing all tasks : `list` +Format: `list [done]` +Shows a list of all tasks done or not done in the task list.
+* `list` shows all tasks not done +* `list done` shows all tasks done +


+ +### Finding all tasks containing any keyword in their name or attributes: `find` +Format: `find [FIELD_TYPE] KEYWORD` +Finds tasks whose descriptions contain any of the given keyword.
+* The search is case sensitive. e.g `hmk` will not match `HMK` +* The order of the keywords does not matter. e.g. `Do Homework` will match `Homework Do` +* If field type is specified, only the field type will be matched with the keyword +* If field type is not specified, name will be search for a match first, before searching all the other fields for the keyword. +* Only full words will be matched e.g. `Hmk` will not match `Hmks` +* Tasks matching at least one keyword will be returned (i.e. `OR` search). + e.g. `Hmk` will match `Do Hmk` + +Examples: +* `find p/3` : Returns any task that has priority 3 +* `find a/NUS` : Returns any task that occurs in NUS +* `find homework`: Returns task with homework in the name, if not found, returns tasks with homework in other fields such as tags +


+ +### Deleting a task : `delete` +Deletes the specified task from the address book. Irreversible.
+Format: `delete INDEX` + +Deletes the task at the specified `INDEX`. +The index refers to the index number shown in the most recent listing.
+The index **must be a positive integer** 1, 2, 3, ... + +Examples: +* `list`
+ `delete 2`
+ Deletes the 2nd task in the task list. +* `find CS2101`
+ `delete 1`
+ Deletes the 1st task in the results of the `find` command. +


+ +### Select a person : `select` +Selects the person identified by the index number used in the last person listing.
+Format: `select INDEX` + +Selects the person and loads the Google Maps for location of the task at the specified `INDEX`. +The index refers to the index number shown in the most recent listing.
+The index **must be a positive integer** 1, 2, 3, ... + +Examples: +* `list`
+ `select 2`
+ Selects the 2nd task in the task list. +* `find a/NUS`
+ `select 1`
+ Selects the 1st task in the results of the `find` command. +


+ +### Clearing all entries : `clear` +Clears all entries from the task list.
+Format: `clear` +


+ +### Change file path of storage : `setPath` +Change the path of the task list to be stored to the specified file path.
+Format: `setPath NEW_PATH` +Example: +* `setPath data/newfilepath.xml` +


+ +### Exiting the program : `exit` +Exits the program.
+Format: `exit` +


+ +### Saving the data +Task List data are saved in the hard disk automatically after any command that changes the data.
+There is no need to save manually. +


+ +## 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 Tasks folder. +

+## Command Summary + +Command | Format +-------- | :-------- +Add | `add NAME [s/startdate d/duedate a/address p/priorityrank(1- highest,5-lowest) t/TAG]...` +Edit | `edit INDEX [NEW_NAME] FIELD_TYPE/NEW_FIELD_DETAILS` where FIELD_TYPE is either `d/` `a/` `s/` `p/` +Done | `done INDEX` +Clear | `clear` +Delete | `delete INDEX` +Find | `find [FIELD_TYPE] KEYWORD` FIELD_TYPE options: `t/` `a/` `s/` `d/` `p/` +List | `list [done]` +Help | `help` +Select | `select INDEX` +SetPath | `setPath NEW_FILE_PATH` NEW_FILE_PATH: e.g. `data/newfile.xml` +Exit | `exit` +``` diff --git a/collated/docs/A0139072H.md b/collated/docs/A0139072H.md new file mode 100644 index 000000000000..9f6f7cd12314 --- /dev/null +++ b/collated/docs/A0139072H.md @@ -0,0 +1,37 @@ +# A0139072H +###### /DeveloperGuide.md +``` md +
+``` +###### /DeveloperGuide.md +``` md +
+``` +###### /DeveloperGuide.md +``` md + +``` +###### /DeveloperGuide.md +``` md + +``` +###### /DeveloperGuide.md +``` md +
+``` +###### /DeveloperGuide.md +``` md +
+``` +###### /DeveloperGuide.md +``` md +
+``` +###### /DeveloperGuide.md +``` md +
+``` +###### /DeveloperGuide.md +``` md +
+``` diff --git a/collated/docs/A0146130W.md b/collated/docs/A0146130W.md new file mode 100644 index 000000000000..0c167fad9ea8 --- /dev/null +++ b/collated/docs/A0146130W.md @@ -0,0 +1,51 @@ +# A0146130W +###### /DeveloperGuide.md +``` md + +## Appendix A : User Stories + +Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` + +Priority | As a ... | I want to ... | So that I can... +-------- | :-------- | :--------- | :----------- +`* * *` | new user | see usage instructions | refer to instructions when I forget how to use the application +`* * *` | user | add a task with a deadline | be reminded of tasks that I have to complete soon and prioritise them +`* * ` | user | add a task with a priority rank | view a prioritised list of tasks and know which task to start with +`* * ` | user | add a task with a location | immediately know the location and context without having to refer to other sources +`* * *` | user | add a task with tag(s) | search or filter tasks by these tags +`* * ` | user | select a task to access widgets like Google Calendar and Google Maps | immediately connect with these frequently used applications, without having to take more steps such as opening a browser and visiting the link, and typing in the search bar +`* * *` | user | delete a task | remove clutter from the task list +`* * *` | user | find a task by title | find tasks easily +`* * *` | user | find a task by tags | categorise and find tasks easily +`* * *` | user | edit information about a task | update the task (such as adding a deadline or location) when more information is available or when changes arise +`* * *` | user | view all tasks entered | have a quick summary of what tasks I have +`* * *` | user | clear all tasks | reset the task list + +``` +###### /DeveloperGuide.md +``` md + +## Appendix E : Product Survey + +Reminders for Mac: Simple, clean white interface that is close to a text editor. Mouse use for interaction only required for tags, adding and deleting. +Features: +a) tags can be added to items on the list like date due and priority +b) schedule tab can arrange the reminders by due date +c) iCloud sync allows use on laptop and phone +d) periodic tasks can be set such that a reminder alert is displayed every time it is due. + +Drawbacks: +a) Need to refer to calendar to set due dates. + +Asana: Collaborative GTD, a team can set up project tasks and subgroups that divide people into smaller groups based on tasks (Marketing, Engineering, etc). +a) Can setup individual tasks on personal dashboard, so it also works well for individual use. +b) Can hold conversations with team members. +c) Can set up team tasks. +d) Can divide members into smaller groups for better organisation. + +Taskwarrior: feature-rich software that allows the user to manage his todo list from the command line. +Uses a natural and expressive syntax +Allows user to perform CRUD functions and prioritising of tasks in a fast manner +Support for creating deadlines, searching of tasks +However, it does not support Jim’s need for “blocking� and “unblocking� timeslots +``` diff --git a/collated/docs/addressbooklevel4.md b/collated/docs/addressbooklevel4.md new file mode 100644 index 000000000000..f7f93106178c --- /dev/null +++ b/collated/docs/addressbooklevel4.md @@ -0,0 +1,258 @@ +# addressbooklevel4 +###### /DeveloperGuide.md +``` md +The **_Architecture Diagram_** given above explains the high-level design of the App. +Given below is a quick overview of each component. + +`Main` has only one class called [`MainApp`](../src/main/java/seedu/address/MainApp.java). It is responsible for, +* At app launch: Initializes the components in the correct sequence, and connect them up with each other. +* At shut down: Shuts down the components and invoke cleanup method where necessary. + +[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components. +Two of those classes play important roles at the architecture level. +* `EventsCentre` : This class (written using [Google's Event Bus library](https://github.com/google/guava/wiki/EventBusExplained)) + is used by components to communicate with other components using events (i.e. a form of _Event Driven_ design) +* `LogsCenter` : Used by many classes to write log messages to the App's log file. + +The rest of the App consists four components. +* [**`UI`**](#ui-component) : The UI of tha App. +* [**`Logic`**](#logic-component) : The command executor. +* [**`Model`**](#model-component) : Holds the data of the App in-memory. +* [**`Storage`**](#storage-component) : Reads data from, and writes data to, the hard disk. + +Each of the four components +* Defines its _API_ in an `interface` with the same name as the Component. +* Exposes its functionality using a `{Component Name}Manager` class. + +For example, the `Logic` component (see the class diagram given below) defines it's API in the `Logic.java` +interface and exposes its functionality using the `LogicManager.java` class.
+``` +###### /DeveloperGuide.md +``` md + +The _Sequence Diagram_ below shows how the components interact for the scenario where the user issues the +command `delete 3`. +``` +###### /DeveloperGuide.md +``` md + +>Note how the `Model` simply raises a `AddressBookChangedEvent` when the GTD data are changed, + instead of asking the `Storage` to save the updates to the hard disk. + +The diagram below shows how the `EventsCenter` reacts to that event, which eventually results in the updates +being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
+``` +###### /DeveloperGuide.md +``` md + +> Note how the event is propagated through the `EventsCenter` to the `Storage` and `UI` without `Model` having + to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct + coupling between components. + +The sections below give more details of each component. + +### UI component +``` +###### /DeveloperGuide.md +``` md + +**API** : [`Ui.java`](../src/main/java/seedu/address/ui/Ui.java) + +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `TaskListPanel`, +`StatusBarFooter`, `BrowserPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class +and they can be loaded using the `UiPartLoader`. + +The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files + that are in the `src/main/resources/view` folder.
+ For example, the layout of the [`MainWindow`](../src/main/java/seedu/address/ui/MainWindow.java) is specified in + [`MainWindow.fxml`](../src/main/resources/view/MainWindow.fxml) + +The `UI` component, +* Executes user commands using the `Logic` component. +* Binds itself to some data in the `Model` so that the UI can auto-update when data in the `Model` change. +* Responds to events raised from various parts of the App and updates the UI accordingly. + +### Logic component +``` +###### /DeveloperGuide.md +``` md +**API** : [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java) + +1. `Logic` uses the `Parser` class to parse the user command. +2. This results in a `Command` object which is executed by the `LogicManager`. +3. The command execution can affect the `Model` (e.g. adding a task) and/or raise events. +4. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. + +Given below is the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` + API call.
+``` +###### /DeveloperGuide.md +``` md +### Model component +``` +###### /DeveloperGuide.md +``` md +**API** : [`Model.java`](../src/main/java/seedu/address/model/Model.java) + +The `Model`, +* stores a `UserPref` object that represents the user's preferences. +* stores the GTD data. +* exposes a `UnmodifiableObservableList` that can be 'observed' e.g. the UI can be bound to this list + so that the UI automatically updates when the data in the list change. +* does not depend on any of the other three components. + +### Storage component +``` +###### /DeveloperGuide.md +``` md +**API** : [`Storage.java`](../src/main/java/seedu/address/storage/Storage.java) + +The `Storage` component, +* can save `UserPref` objects in json format and read it back. +* can save the GTD data in xml format and read it back. + +### Common classes + +Classes used by multiple components are in the `seedu.addressbook.commons` package. + +## Implementation + +### Logging + +We are using `java.util.logging` package for logging. The `LogsCenter` class is used to manage the logging levels +and logging destinations. + +* The logging level can be controlled using the `logLevel` setting in the configuration file + (See [Configuration](#configuration)) +* The `Logger` for a class can be obtained using `LogsCenter.getLogger(Class)` which will log messages according to + the specified logging level +* Currently log messages are output through: `Console` and to a `.log` file. + +**Logging Levels** + +* `SEVERE` : Critical problem detected which may possibly cause the termination of the application +* `WARNING` : Can continue, but with caution +* `INFO` : Information showing the noteworthy actions by the App +* `FINE` : Details that is not usually noteworthy but may be useful in debugging + e.g. print the actual list instead of just its size + +### Configuration + +Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file +(default: `config.json`): + + +## Testing + +Tests can be found in the `./src/test/java` folder. + +**In Eclipse**: +> If you are not using a recent Eclipse version (i.e. _Neon_ or later), enable assertions in JUnit tests + as described [here](http://stackoverflow.com/questions/2522897/eclipse-junit-ea-vm-option). + +* To run all tests, right-click on the `src/test/java` folder and choose + `Run as` > `JUnit Test` +* To run a subset of tests, you can right-click on a test package, test class, or a test and choose + to run as a JUnit test. + +**Using Gradle**: +* See [UsingGradle.md](UsingGradle.md) for how to run tests using Gradle. + +We have two types of tests: + +1. **GUI Tests** - These are _System Tests_ that test the entire App by simulating user actions on the GUI. + These are in the `guitests` package. + +2. **Non-GUI Tests** - These are tests not involving the GUI. They include, + 1. _Unit tests_ targeting the lowest level methods/classes.
+ e.g. `seedu.address.commons.UrlUtilTest` + 2. _Integration tests_ that are checking the integration of multiple code units + (those code units are assumed to be working).
+ e.g. `seedu.address.storage.StorageManagerTest` + 3. Hybrids of unit and integration tests. These test are checking multiple code units as well as + how the are connected together.
+ e.g. `seedu.address.logic.LogicManagerTest` + +**Headless GUI Testing** : +Thanks to the [TestFX](https://github.com/TestFX/TestFX) library we use, + our GUI tests can be run in the _headless_ mode. + In the headless mode, GUI tests do not show up on the screen. + That means the developer can do other things on the Computer while the tests are running.
+ See [UsingGradle.md](UsingGradle.md#running-tests) to learn how to run tests in headless mode. + +## Dev Ops + +### Build Automation + +See [UsingGradle.md](UsingGradle.md) to learn how to use Gradle for build automation. + +### Continuous Integration + +We use [Travis CI](https://travis-ci.org/) to perform _Continuous Integration_ on our projects. +See [UsingTravis.md](UsingTravis.md) for more details. + +### Making a Release + +Here are the steps to create a new release. + + 1. Generate a JAR file [using Gradle](UsingGradle.md#creating-the-jar-file). + 2. Tag the repo with the version number. e.g. `v0.1` + 2. [Crete a new release using GitHub](https://help.github.com/articles/creating-releases/) + and upload the JAR file your created. + +### Managing Dependencies + +A project often depends on third-party libraries. For example, Tarydepends on the +[Jackson library](http://wiki.fasterxml.com/JacksonHome) for XML parsing. Managing these _dependencies_ +can be automated using Gradle. For example, Gradle can download the dependencies automatically, which +is better than these alternatives.
+a. Include those libraries in the repo (this bloats the repo size)
+b. Require developers to download those libraries manually (this creates extra work for developers)
+ +``` +###### /DeveloperGuide.md +``` md + +## Appendix B : Use Cases + +(For all use cases below, the **System** is the `GTD` and the **Actor** is the `user`, unless specified otherwise) + +#### Use case: Delete task + +**MSS** + +1. User requests to list persons +2. GTD shows a list of persons +3. User requests to delete a specific person in the list +4. GTD deletes the person
+Use case ends. + +**Extensions** + +2a. The list is empty + +> Use case ends + +3a. The given index is invalid + +> 3a1. GTD shows an error message
+ Use case resumes at step 2 + +{More to be added} + +## Appendix C : Non Functional Requirements + +1. Should work on any [mainstream OS](#mainstream-os) as long as it has Java `1.8.0_60` or higher installed. +2. Should be able to hold up to 10,000 tasks. +3. Should come with automated unit tests and open source code. +4. Should favor DOS style commands over Unix-style commands. + +{More to be added} + +## Appendix D : Glossary + +##### Mainstream OS + +> Windows, Linux, Unix, OS-X + +``` diff --git a/collated/main/A0130677A.md b/collated/main/A0130677A.md new file mode 100644 index 000000000000..ceaf8f652bae --- /dev/null +++ b/collated/main/A0130677A.md @@ -0,0 +1,638 @@ +# A0130677A +###### /seedu/gtd/logic/commands/AddCommand.java +``` java +public class AddCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a task to the GTD. " + + "Parameters: NAME [s/STARTDATE d/DUEDATE a/ADDRESS p/PRIORITY t/TAGS]...\n" + + "All parameters except name is optional.\n" + + "Example: " + COMMAND_WORD + + " Do CS2103 Tutorial 4 d/noon a/NUS p/3 t/CS2103 tutorial fun"; + + public static final String MESSAGE_SUCCESS = "New task added: %1$s"; + public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task list"; + + private final Task toAdd; + + /** + * Convenience constructor using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, String startDate, String dueDate, String address, String priority, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAdd = new Task( + new Name(name), + new DueDate(startDate), + new DueDate(dueDate), + new Address(address), + new Priority(priority), + new UniqueTagList(tagSet) + ); + } + +``` +###### /seedu/gtd/logic/commands/DoneCommand.java +``` java +public class DoneCommand extends Command { + + public static final String COMMAND_WORD = "done"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Marks a task as done, by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DONE_TASK_SUCCESS = "Done Task: %1$s"; + + public final int targetIndex; + + public DoneCommand(int targetIndex) { + this.targetIndex = targetIndex; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask toEdit = lastShownList.get(targetIndex-1); + Task taskToUpdate = new Task(toEdit); + + try { + taskToUpdate = updateTask(taskToUpdate, "done", "true"); + } catch (IllegalValueException ive) { + return new CommandResult(ive.getMessage()); + } + + assert model != null; + try { + System.out.println("in donecommand.java"); + System.out.println(taskToUpdate.getName() + " " + taskToUpdate.getisDone()); + System.out.println("index at donecommand:" + targetIndex); + model.doneTask(targetIndex-1, taskToUpdate); + + } catch (TaskNotFoundException e) { + assert false : "The target task cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_DONE_TASK_SUCCESS, taskToUpdate)); + + } + + private Task updateTask(Task taskToUpdate, String detailType, String newDetail) throws IllegalValueException { + taskToUpdate.edit(detailType, newDetail); + return taskToUpdate; + } + +} +``` +###### /seedu/gtd/logic/commands/FindCommand.java +``` java +public class FindCommand extends Command { + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose name, date, address, tags and priority contain any of " + + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" + + "To search by one particular field type, use t/ for tags, a/ for address, d/ for duedate and p/ for priority.\n" + + "Parameters: [FIELDTYPE] KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " cs2103, " + COMMAND_WORD + " d/today"; + +``` +###### /seedu/gtd/logic/commands/FindCommand.java +``` java + @Override + public CommandResult execute() { + System.out.println("command: " + cmd); + + // search by parameter if specified + if (cmd != "nil") { + model.updateFilteredTaskList(keywords, cmd); + } else { + // search by exact name + model.updateFilteredTaskList(keywords, keywordSet); + } + if (!model.getFilteredTaskList().isEmpty()) { + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } + + // search by keywords + model.updateFilteredTaskList(keywords, "nil"); + + if (!model.getFilteredTaskList().isEmpty()) { + if (cmd == "nil") { + return new CommandResult(getMessageForTaskListShownSummaryIfExactPhraseNotFound(model.getFilteredTaskList().size())); + } else { + return new CommandResult(getMessageForTaskListShownSummaryIfExactFieldNotFound(model.getFilteredTaskList().size())); + } + } + + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } +} +``` +###### /seedu/gtd/logic/commands/ListCommand.java +``` java + +public class ListCommand extends Command { + + public static final String COMMAND_WORD = "list"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows a list of all tasks in the task list."; + public static final String MESSAGE_SUCCESS_LIST = "Listed all undone tasks"; + public static final String MESSAGE_SUCCESS_LIST_DONE = "Listed all tasks done"; + private String arg; + + public ListCommand(String arg) { + this.arg = arg; + } + + @Override + public CommandResult execute() { + System.out.println("args:" + arg); + if (arg.equals(" done")) { + System.out.println("in done"); + model.updateFilteredListToShowRemoved(); + return new CommandResult(MESSAGE_SUCCESS_LIST_DONE); + } else { + model.updateFilteredListToShowUndone(); + return new CommandResult(MESSAGE_SUCCESS_LIST); + } + } +} +``` +###### /seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java +``` java + public Date getDate(String naturalLanguageDate) { + List dateGroups = parser.parse(naturalLanguageDate); + Date parsedDate; + try { + parsedDate = refineDateGroupList(dateGroups); + return parsedDate; + } catch (NaturalLanguageException e) { + return null; + } + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + private static final Pattern NAME_TASK_DATA_ARGS_FORMAT = + Pattern.compile("(?[^/]+) (s|t|p|a|d|z)/.*"); + + private static final Pattern PRIORITY_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* p/(?[^/]+) (s|t|a|d|z)/.*"); + + private static final Pattern ADDRESS_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* a/(?
[^/]+) (s|t|p|d|z)/.*"); + + private static final Pattern STARTDATE_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* s/(?[^/]+) (d|t|a|p|z)/.*"); + + private static final Pattern DUEDATE_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* d/(?[^/]+) (s|t|a|p|z)/.*"); + + private static final Pattern TAGS_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* t/(?[^/]+) (s|d|a|p|z)/.*"); + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + private Command prepareAdd(String args){ + String preprocessedArg = appendEnd(args.trim()); + + final Matcher nameMatcher = NAME_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher startDateMatcher = STARTDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + + String nameToAdd = checkEmptyAndAddDefault(nameMatcher, "name", "nil"); + String startDateToAdd = checkEmptyAndAddDefault(startDateMatcher, "startDate", "nil"); + String dueDateToAdd = checkEmptyAndAddDefault(dueDateMatcher, "dueDate", "nil"); + String addressToAdd = checkEmptyAndAddDefault(addressMatcher, "address", "nil"); + String priorityToAdd = checkEmptyAndAddDefault(priorityMatcher, "priority", "1"); + + // format date if due date or start date is specified + + Date dueDateInDateFormat = null; + Date startDateInDateFormat = null; + + if (dueDateMatcher.matches()) { + dueDateInDateFormat = getDateInDateFormat(dueDateToAdd); + dueDateToAdd = parseDueDate(dueDateToAdd); + System.out.println(dueDateInDateFormat); + } + + if (startDateMatcher.matches()) { + startDateInDateFormat = getDateInDateFormat(startDateToAdd); + startDateToAdd = parseDueDate(startDateToAdd); + } + + // check that end date is strictly later than start date + + if (dueDateInDateFormat != null && startDateInDateFormat != null + && dueDateInDateFormat.compareTo(startDateInDateFormat) < 0) { + return new IncorrectCommand(START_END_DATE_INVALID_COMMAND_FORMAT); + } + + Set tagsProcessed = Collections.emptySet(); + + if (tagsMatcher.matches()) { + tagsProcessed = getTagsFromArgs(tagsMatcher.group("tagArguments")); + } + + + // Validate arg string format + if (!nameMatcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + + try { + return new AddCommand( + nameToAdd, + startDateToAdd, + dueDateToAdd, + addressToAdd, + priorityToAdd, + tagsProcessed + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + private String appendEnd(String args) { + return args + " z/"; + } + + private String checkEmptyAndAddDefault(Matcher matcher, String groupName, String defaultValue) { + if (matcher.matches()) { + return matcher.group(groupName); + } else { + return defaultValue; + } + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + private Date getDateInDateFormat(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.getDate(dueDateRaw); + } + + // remove time on date parsed to improve search results + private String removeTimeOnDate(String dueDateRaw) { + String[] dateTime = dueDateRaw.split(" "); + return dateTime[0]; + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + private Command prepareDone(String args) { + + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DoneCommand.MESSAGE_USAGE)); + } + + return new DoneCommand(index.get()); + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + private Command prepareFind(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + String preprocessedArgs = " " + appendEnd(args.trim()); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher startDateMatcher = STARTDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + + Set defaultSet = new HashSet(); + + if (addressMatcher.matches()) { + String addressToBeFound = addressMatcher.group("address"); + return new FindCommand(addressToBeFound, defaultSet,"address"); + } + if (priorityMatcher.matches()) { + String priorityToBeFound = priorityMatcher.group("priority"); + return new FindCommand(priorityToBeFound, defaultSet, "priority"); + } + if (startDateMatcher.matches()) { + String dueDateToBeFound = dueDateMatcher.group("startDate"); + String parsedDueDateToBeFound = removeTimeOnDate(parseDueDate(dueDateToBeFound)); + return new FindCommand(parsedDueDateToBeFound, defaultSet, "startDate"); + } + if (dueDateMatcher.matches()) { + String dueDateToBeFound = dueDateMatcher.group("dueDate"); + String parsedDueDateToBeFound = removeTimeOnDate(parseDueDate(dueDateToBeFound)); + return new FindCommand(parsedDueDateToBeFound, defaultSet, "dueDate"); + } + if (tagsMatcher.matches()) { + String tagsToBeFound = tagsMatcher.group("tagArguments"); + return new FindCommand(tagsToBeFound, defaultSet,"tagArguments"); + } + + // free-form search by keywords + + final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + // keywords delimited by whitespace + final String[] splitKeywords = matcher.group("keywords").split("\\s+"); + final Set keywordSet = new HashSet<>(Arrays.asList(splitKeywords)); + + final String keywords = matcher.group("keywords"); + return new FindCommand(keywords, keywordSet, "nil"); + } + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + + @Override + public synchronized void doneTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.doneTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + + @Override + public void updateFilteredListToShowAll() { + filteredTasks.setPredicate(null); + updateFilteredListToShowAll(new PredicateExpression(new AllQualifiers())); + //updateFilteredListToShowAll(null); + System.out.println("show all"); + } + + private void updateFilteredListToShowAll(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowRemoved() { + updateFilteredListToShowRemoved(new PredicateExpression(new DoneQualifier())); + } + + private void updateFilteredListToShowRemoved(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowUndone() { + updateFilteredListToShowUndone(new PredicateExpression(new RemoveDoneQualifier())); + } + + private void updateFilteredListToShowUndone(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredTaskList(Set keywordSet) { + updateFilteredTaskList(new PredicateExpression(new NameQualifier(keywordSet))); + } + + @Override + public void updateFilteredTaskList(String keywords, Set keywordSet){ + updateFilteredTaskList(new PredicateExpression(new orderedNameQualifier(keywords, keywordSet))); + } + + @Override + public void updateFilteredTaskList(String keywords, String cmd) { + updateFilteredTaskList(new PredicateExpression(new otherFieldsQualifier(keywords, cmd))); + } + + private void updateFilteredTaskList(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + //========== Inner classes/interfaces used for filtering ================================================== + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + + private class otherFieldsQualifier implements Qualifier { + protected String nameKeyWords; + protected String cmd; + + otherFieldsQualifier(String keywords, String cmd) { + this.nameKeyWords = keywords; + this.cmd = cmd; + } + + @Override + public boolean run(ReadOnlyTask task) { + if (cmd == "address") { + System.out.println("finding address.."); + String address = task.getAddress().toString().toLowerCase(); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + return addressMatch; + } else if (cmd == "priority") { + System.out.println("finding priority.."); + String priority = task.getPriority().toString(); + boolean priorityMatch = priority.contains(nameKeyWords); + return priorityMatch; + } else if (cmd == "dueDate") { + System.out.println("finding dueDate.."); + String dueDate = task.getDueDate().toString(); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + return dueDateMatch; + } else if (cmd == "tagArguments") { + System.out.println("finding tags.. "); + UniqueTagList tagsList = task.getTags(); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + return tagsMatch; + } + + // cmd == "nil" + + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + String priority = task.getPriority().toString(); + String address = task.getAddress().toString().toLowerCase(); + String dueDate = task.getDueDate().toString(); + UniqueTagList tagsList = task.getTags(); + + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + boolean priorityMatch = priority.contains(nameKeyWords); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + boolean eachWordMatch = false; + + String[] eachWord = nameKeyWords.split(" "); + for (String word : eachWord) { + System.out.println("each: " + word); + eachWordMatch = eachWordMatch || taskFullNameLowerCase.contains(word.toLowerCase()); + } + + return eachWordMatch || nameMatch || addressMatch || priorityMatch || dueDateMatch || tagsMatch; + } + } + + private class orderedNameQualifier extends NameQualifier implements Qualifier { + private String nameKeyWords; + + orderedNameQualifier(String keywords, Set keywordSet) { + super(keywordSet); + this.nameKeyWords = keywords; + } + + @Override + public boolean run(ReadOnlyTask task) { + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + + boolean eachWordMatch = keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); + return eachWordMatch && nameMatch; + } + } + private class AllQualifiers implements Qualifier { + + AllQualifiers() {} + + @Override + public boolean run(ReadOnlyTask task) { + return true; + } + } + + // to check and return a list of tasks that are already done + private class DoneQualifier implements Qualifier { + + DoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + return task.getisDone(); + } + } + + // default display tasks that are not yet done + private class RemoveDoneQualifier implements Qualifier { + + RemoveDoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + System.out.println(task.getName()); + return !task.getisDone(); + //return task.getisDone(); + + } + } + @Override +``` +###### /seedu/gtd/model/task/Priority.java +``` java + public static final String MESSAGE_PRIORITY_CONSTRAINTS = "Task priority number should only contain a number from 1 to 5"; + public static final String PRIORITY_VALIDATION_REGEX = "\\d{1}"; + public static final int MAX_PRIORITY = 5; + public static final int MIN_PRIORITY = 1; + +``` +###### /seedu/gtd/model/task/Priority.java +``` java + public static boolean isValidPriority(String test) { + return test.matches(PRIORITY_VALIDATION_REGEX) && + Integer.parseInt(test) >= MIN_PRIORITY && Integer.parseInt(test) <= MAX_PRIORITY; + } +``` +###### /seedu/gtd/storage/XmlAdaptedTask.java +``` java + @XmlElement(required = true) + private String name; + @XmlElement(required = true) + private String startDate; + @XmlElement(required = true) + private String dueDate; + @XmlElement(required = true) + private String address; + @XmlElement(required = true) + private String priority; + @XmlElement(required = true) + private boolean isDone; + + @XmlElement + private List tagged = new ArrayList<>(); + + /** + * No-arg constructor for JAXB use. + */ + public XmlAdaptedTask() {} + + + /** + * Converts a given Task into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedTask + */ + public XmlAdaptedTask(ReadOnlyTask source) { + name = source.getName().fullName; + startDate = source.getStartDate().value; + dueDate = source.getDueDate().value; + address = source.getAddress().value; + priority = source.getPriority().value; + isDone = source.getisDone(); + tagged = new ArrayList<>(); + for (Tag tag : source.getTags()) { + tagged.add(new XmlAdaptedTag(tag)); + } + } + + /** + * Converts this jaxb-friendly adapted task object into the model's Task object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted task + */ + public Task toModelType() throws IllegalValueException { + final List taskTags = new ArrayList<>(); + for (XmlAdaptedTag tag : tagged) { + taskTags.add(tag.toModelType()); + } + final Name name = new Name(this.name); + final DueDate startDate = new DueDate(this.startDate); + final DueDate dueDate = new DueDate(this.dueDate); + final Address address = new Address(this.address); + final Priority priority = new Priority(this.priority); + final boolean isDone = this.isDone; + System.out.println("printed isdone as: " + isDone); + final UniqueTagList tags = new UniqueTagList(taskTags); + return new Task(name, startDate, dueDate, address, priority, tags, isDone); + } +} +``` diff --git a/collated/main/A0139072H.md b/collated/main/A0139072H.md new file mode 100644 index 000000000000..5dcc44da8f86 --- /dev/null +++ b/collated/main/A0139072H.md @@ -0,0 +1,127 @@ +# A0139072H +###### /seedu/gtd/logic/commands/SetFilePathCommand.java +``` java + +/** + * Sets the file path of the saved tasklist to a new file + **/ +public class SetFilePathCommand extends Command { + + public static final String COMMAND_WORD = "setPath"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": sets the new file location. " + + "Parameters: nameofnewfile\n" + + "Example: " + COMMAND_WORD + + " internalFolder/name_of_new_file"; + + public static final String MESSAGE_SUCCESS = "New file location set to: %1$s"; + public static final String MESSAGE_INVALID_LOC_TASK = "The file location is invalid!"; + + private final String newFilePath; + + /** + * Convenience constructor using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public SetFilePathCommand(String givenString) + throws IllegalValueException { + this.newFilePath = givenString.trim(); + } + + @Override + public CommandResult execute() { + assert model != null; + try{ + model.setFilePathTask(newFilePath); + } catch (Exception e) { + return new CommandResult(MESSAGE_INVALID_LOC_TASK); + } + return new CommandResult(String.format(MESSAGE_SUCCESS, newFilePath)); + } + +} +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + /** + * Parses arguments in the context of the setFilePath command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareSetFilePath(String args) { + if(args.equals("")){ + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SetFilePathCommand.MESSAGE_USAGE)); + } + final String filePath = args; + try { + return new SetFilePathCommand(filePath); + } catch (IllegalValueException e) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SetFilePathCommand.MESSAGE_USAGE)); + } + } + +} +``` +###### /seedu/gtd/model/AddressBook.java +``` java +//// application-wide operations + public void setFilePathTask(String newFilePath) throws IOException{ + Config changedConfig; + String configFilePathUsed; + + System.out.println("SetFilePathTask"); + +``` +###### /seedu/gtd/model/AddressBook.java +``` java + //Save the config back to the file + ConfigUtil.saveConfig(changedConfig, configFilePathUsed); + StorageManager newSaveMgr = new StorageManager( + new XmlAddressBookStorage(newFilePath), + new JsonUserPrefsStorage(changedConfig.getUserPrefsFilePath()) + ); + //Save the addressBook to the new location + newSaveMgr.saveAddressBook(this); + }; + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + //application-wide operations + public void setFilePathTask(String newFilePath) throws IOException{ + addressBook.setFilePathTask(newFilePath); + indicateAddressBookChanged(); + //NEEDS TO SAVE TO NEW FILEPATH + }; +} +``` +###### /seedu/gtd/ui/BrowserPanel.java +``` java + public void loadPage(){ + browser.getEngine().load("http://calendar.google.com"); + } + +``` +###### /seedu/gtd/ui/MainWindow.java +``` java + private static final String ICON = "/images/tary.png"; + +``` +###### /seedu/gtd/ui/MainWindow.java +``` java + /** + * Launches the calendar. + */ + @FXML + private void handleCal() { + browserPanel.loadPage(); + } + +``` +###### /seedu/gtd/ui/UiManager.java +``` java + private static final String ICON_APPLICATION = "/images/tary.png"; + +``` diff --git a/collated/main/A0139158X.md b/collated/main/A0139158X.md new file mode 100644 index 000000000000..8bf72a2f66f3 --- /dev/null +++ b/collated/main/A0139158X.md @@ -0,0 +1,74 @@ +# A0139158X +###### /seedu/gtd/logic/commands/HelpCommand.java +``` java +public class HelpCommand extends Command { + + public static final String COMMAND_WORD = "help"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" + + "Parameters: COMMANDWORD\n" + + "Example: " + COMMAND_WORD + " add"; + + public static final String SHOWING_HELP_MESSAGE = "Opened help window."; + + public final String argument; + + public HelpCommand(String arg) { + this.argument=arg; + } + + @Override + public CommandResult execute() { + + switch (argument) { + + case AddCommand.COMMAND_WORD: + return new CommandResult(AddCommand.MESSAGE_USAGE); + + case SelectCommand.COMMAND_WORD: + return new CommandResult(SelectCommand.MESSAGE_USAGE); + + case DeleteCommand.COMMAND_WORD: + return new CommandResult(DeleteCommand.MESSAGE_USAGE); + + case ClearCommand.COMMAND_WORD: + return new CommandResult(ClearCommand.MESSAGE_USAGE); + + case FindCommand.COMMAND_WORD: + return new CommandResult(FindCommand.MESSAGE_USAGE); + + case ListCommand.COMMAND_WORD: + return new CommandResult(ListCommand.MESSAGE_USAGE); + + case ExitCommand.COMMAND_WORD: + return new CommandResult(ExitCommand.MESSAGE_USAGE); + + case HelpCommand.COMMAND_WORD: + EventsCenter.getInstance().post(new ShowHelpRequestEvent()); + return new CommandResult(MESSAGE_USAGE+"/n"+SHOWING_HELP_MESSAGE); + + default: + EventsCenter.getInstance().post(new ShowHelpRequestEvent()); + return new CommandResult(MESSAGE_USAGE+"/n"+SHOWING_HELP_MESSAGE); + } + } +} +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + private Command prepareHelp(String args) { + //if no argument + if (args.equals("")) { + args="help"; + } + + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + return new HelpCommand(commandWord); + } + +``` diff --git a/collated/main/A0146130W.md b/collated/main/A0146130W.md new file mode 100644 index 000000000000..416c34bdd023 --- /dev/null +++ b/collated/main/A0146130W.md @@ -0,0 +1,384 @@ +# A0146130W +###### /seedu/gtd/commons/exceptions/DataConversionException.java +``` java + public DataConversionException(String cause) { + super(cause); + } +} +``` +###### /seedu/gtd/logic/commands/EditCommand.java +``` java + /** + * Adds a task to the address book. + */ + public class EditCommand extends Command { + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ":\n" + + "Edits the task identified by the index number used in the last task listing.\n\t" + + "Parameters: [INDEX] (must be a positive integer) prefix/[NEW DETAIL]\n\t" + + "Example: " + COMMAND_WORD + + " 1 p/3"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Task updated: %1$s"; + + private int targetIndex; + private Hashtable newDetails; + + public EditCommand(int targetIndex, Hashtable newDetails) { + this.targetIndex = targetIndex; + this.newDetails = newDetails; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask toEdit = lastShownList.get(targetIndex); + Task taskToUpdate = new Task(toEdit); + + assert model != null; + try { + Set detailTypes = newDetails.keySet(); + for(String detailType : detailTypes) { + System.out.println("from edit command: " + detailType + " " + newDetails.get(detailType)); + taskToUpdate = updateTask(taskToUpdate, detailType, newDetails.get(detailType)); + model.editTask(targetIndex, taskToUpdate); + } + } catch (IllegalValueException ive) { + return new CommandResult(ive.getMessage()); + } catch (TaskNotFoundException e) { + assert false : "The target task cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToUpdate)); + } + + private Task updateTask(Task taskToUpdate, String detailType, String newDetail) throws IllegalValueException { + taskToUpdate.edit(detailType, newDetail); + return taskToUpdate; + } + + } +``` +###### /seedu/gtd/logic/commands/FindCommand.java +``` java + private final String keywords; + private Set keywordSet; + private final String cmd; + + public FindCommand(String keywords, Set keywordSet, String cmd) { + this.keywords = keywords; + this.keywordSet = keywordSet; + this.cmd = cmd; + } + + private String getMessageForTaskListShownSummaryIfExactPhraseNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } + + private String getMessageForTaskListShownSummaryIfExactFieldNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found in the specified field type. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } + + +``` +###### /seedu/gtd/logic/commands/UndoCommand.java +``` java + +package seedu.gtd.logic.commands; + +/** + * Deletes a task identified using it's last displayed index from the address book. + */ +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Un-does the most recent modification of the task list."; + public static final String MESSAGE_SUCCESS = "Undo change"; + public static final String MESSAGE_UNDO_LIMIT_REACHED = "Undo limit reached!"; + + public UndoCommand() {} + + @Override + public CommandResult execute() { + if(model.undoAddressBookChange()) return new CommandResult(MESSAGE_SUCCESS); + else return new CommandResult(MESSAGE_UNDO_LIMIT_REACHED); + } + +} +``` +###### /seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java +``` java + +/** + * Uses natty API: http://natty.joestelmach.com to parse natural language into dates or string + */ +public class DateNaturalLanguageProcessor implements NaturalLanguageProcessor { + + private static final com.joestelmach.natty.Parser parser = new com.joestelmach.natty.Parser(); + private static final String DATE_FORMAT = "dd/MM/yyyy HH:mm"; + + @Override + public String formatString(String naturalLanguageDate) { + List dateGroups = parser.parse(naturalLanguageDate); + Date parsedDate; + try { + parsedDate = refineDateGroupList(dateGroups); + } catch (NaturalLanguageException e) { + return ""; + } + return formatDateToString(parsedDate); + } + +``` +###### /seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java +``` java + + /** + * Chooses the first date from a list of dates that Natty has parsed from the natural language string + * @throws NaturalLanguageException + * */ + private Date refineDateGroupList(List groups) throws NaturalLanguageException { + if(groups.size() == 0) throw new NaturalLanguageException(); + return groups.get(0).getDates().get(0); + } + + private String formatDateToString(Date date) { + Format formatter = new SimpleDateFormat(DATE_FORMAT); + return formatter.format(date); + } +} +``` +###### /seedu/gtd/logic/parser/NaturalLanguageProcessor.java +``` java + +package seedu.gtd.logic.parser; + +import java.util.Date; + +import seedu.gtd.commons.exceptions.DataConversionException; + +public interface NaturalLanguageProcessor { + + /** Takes in a string written in natural language and formats it.*/ + String formatString(String s); + Date getDate(String dueDateRaw); + + public static class NaturalLanguageException extends DataConversionException { + protected NaturalLanguageException() { + super("Natural Language Processor was unable to convert input"); + } + } +} +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + private String parseDueDate(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.formatString(dueDateRaw); + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + /** + * Parses arguments in the context of the edit task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareEdit(String args) { + + Optional index = parseIndex(args, EDIT_DATA_ARGS_FORMAT); + final Matcher matcher = EDIT_DATA_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + + final String[] splitNewDetails = matcher.group("newDetails").split("\\s+"); + ArrayList combinedDetails = combineSameDetails(splitNewDetails); + + Hashtable newDetailsSet = new Hashtable(); + + for (String detail : combinedDetails) { + String detailType = extractDetailType(detail); + String preparedNewDetail = prepareNewDetail(detailType, detail); + System.out.println("before adding to hashtable: " + detailType + " " + preparedNewDetail); + newDetailsSet.put(detailType, preparedNewDetail); + } + + return new EditCommand( + index.get()-1, + newDetailsSet + ); + } + + private ArrayList combineSameDetails(String[] details) { + ArrayList alDetails = new ArrayList(Arrays.asList(details)); + System.out.println(alDetails.toString()); + + String name = new String(); + String address = new String(); + String dueDate = new String(); + String priority = new String(); + + int currentDetailType = 0; + + if(alDetails.size() == 1) { + return alDetails; + } + + for (String detail: alDetails) { + System.out.println("detail: " + detail); + + if(extractDetailType(detail).equals("name")) { + System.out.println("current detail type: " + currentDetailType); + switch(currentDetailType) { + case 1: address = address + " " + detail; break; + case 2: dueDate = dueDate + " " + detail; break; + case 3: priority = priority + " " + detail; break; + default: { + if(name.isEmpty()) name = detail; + else name = name + " " + detail; + break; + } + } + } + else if(extractDetailType(detail).equals("address")) { + System.out.println("detected address " + detail); + address = detail; + currentDetailType = 1; + } + else if(extractDetailType(detail).equals("dueDate")) { + System.out.println("detected dueDate " + detail); + dueDate = detail; + currentDetailType = 2; + } + else if(extractDetailType(detail).equals("priority")) { + System.out.println("detected priority " + detail); + address = detail; + currentDetailType = 3; + } + } + + ArrayList finalCombined = new ArrayList(); + //does not remove the separate words from the list, they will be overwritten by the final combined string + if(!name.isEmpty()) finalCombined.add(name); + System.out.println("from combining name: " + name); + if(!address.isEmpty()) finalCombined.add(address); + System.out.println("from combining address: " + address); + if(!dueDate.isEmpty()) finalCombined.add(dueDate); + if(!priority.isEmpty()) finalCombined.add(priority); + + System.out.println("from combining: " + finalCombined.toString()); + return finalCombined; + } + + private String removeDetailPrefix(String detailWithPrefix) { + return detailWithPrefix.substring(detailWithPrefix.indexOf('/') + 1); + } + + private String prepareNewDetail(String detailType, String detailWithPrefix) { + String detail = removeDetailPrefix(detailWithPrefix); + if(detailType.equals("dueDate")) detail = parseDueDate(detail); + return detail; + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + private Optional parseIndex(String command, Pattern matcherFormat) { + final Matcher matcher = matcherFormat.matcher(command.trim()); + if (!matcher.matches()) { + return Optional.empty(); + } + + String index = matcher.group("targetIndex"); + if(!StringUtil.isUnsignedInteger(index)){ + return Optional.empty(); + } + return Optional.of(Integer.parseInt(index)); + + } + +``` +###### /seedu/gtd/model/AddressBook.java +``` java + /** + * Edits a task in the address book. + * Also checks the updated task's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the task to point to those in {@link #tags}. + * + * @throws UniqueTaskList.TaskNotFoundException if the task was not found. + */ + public void editTask(int index, Task t) throws UniqueTaskList.TaskNotFoundException { + syncTagsWithMasterList(t); + tasks.edit(index, t); + } + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + @Override + public synchronized void editTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.editTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + + @Override + public void clearTaskList() { + savePreviousAddressBook(); + resetData(AddressBook.getEmptyAddressBook()); + } + +``` +###### /seedu/gtd/model/task/UniqueTaskList.java +``` java + /** + * Edits an equivalent task from the list. + * + * @throws TaskNotFoundException if no such task could be found in the list. + */ + public void edit(int targetIndex, Task toEdit) throws TaskNotFoundException { + assert toEdit != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + internalList.set(targetIndex, toEdit); + } + + public void done(int targetIndex, Task taskdone) throws TaskNotFoundException { + System.out.println("in uniquetasklist"); + System.out.println(taskdone.getName() + " " + taskdone.getisDone()); + System.out.println("index at final:" + targetIndex); + assert taskdone != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + System.out.println("marked done in model"); + internalList.set(targetIndex, taskdone); + } + + private boolean invalidIndex(int i) { + if(i < 0 || i >= internalList.size()) return true; + return false; + } + +``` diff --git a/collated/main/A0146130Wreused.md b/collated/main/A0146130Wreused.md new file mode 100644 index 000000000000..3772652dbc96 --- /dev/null +++ b/collated/main/A0146130Wreused.md @@ -0,0 +1,23 @@ +# A0146130Wreused +###### /seedu/gtd/logic/parser/Parser.java +``` java + private String extractDetailType(String args) { + String preprocessedArgs = " " + appendEnd(args.trim()); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + + if(addressMatcher.matches()) { + return "address"; + } + else if(dueDateMatcher.matches()) { + return "dueDate"; + } + else if(priorityMatcher.matches()) { + return "priority"; + } + + return "name"; + } + +``` diff --git a/collated/main/addressbooklevel4.md b/collated/main/addressbooklevel4.md new file mode 100644 index 000000000000..d892729b659d --- /dev/null +++ b/collated/main/addressbooklevel4.md @@ -0,0 +1,1081 @@ +# addressbooklevel4 +###### /seedu/gtd/logic/commands/AddCommand.java +``` java + @Override + public CommandResult execute() { + assert model != null; + try { + model.addTask(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } catch (UniqueTaskList.DuplicateTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } + + } + +} +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + /** + * Used for initial separation of command word and args. + */ + private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); + + private static final Pattern TASK_INDEX_ARGS_FORMAT = Pattern.compile("(?.+)"); + + private static final Pattern KEYWORDS_ARGS_FORMAT = + Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace + +// private static final Pattern TASK_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes +// Pattern.compile("(?[^/]+)" +// + " d/(?[^/]+)" +// + " a/(?
[^/]+)" +// + " p/(?[^/]+)" +// + "(?(?: t/[^/]+)*)"); // variable number of tags + + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + private static final Pattern EDIT_DATA_ARGS_FORMAT = + Pattern.compile("(?\\S+)" + + " (?\\S+(?:\\s+\\S+)*)"); + + public Parser() {} + + /** + * Parses user input into command for execution. + * + * @param userInput full user input string + * @return the command based on the user input + */ + public Command parseCommand(String userInput) { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + final String arguments = matcher.group("arguments"); + switch (commandWord) { + + case AddCommand.COMMAND_WORD: + return prepareAdd(arguments); + + case EditCommand.COMMAND_WORD: + return prepareEdit(arguments); + + case SelectCommand.COMMAND_WORD: + return prepareSelect(arguments); + + case DeleteCommand.COMMAND_WORD: + return prepareDelete(arguments); + + case DoneCommand.COMMAND_WORD: + return prepareDone(arguments); + + case ClearCommand.COMMAND_WORD: + return new ClearCommand(); + + case FindCommand.COMMAND_WORD: + return prepareFind(arguments); + + case ListCommand.COMMAND_WORD: + return prepareList(arguments); + + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); + + case HelpCommand.COMMAND_WORD: + return prepareHelp(arguments); + + + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + + case SetFilePathCommand.COMMAND_WORD: + return prepareSetFilePath(arguments); + + + default: + return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); + } + } + + /** + * Parses arguments in the context of the add task command. + * + * @param args full command args string + * @return the prepared command + */ + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + /** + * Extracts the new task's tags from the add command's tag arguments string. + * Merges duplicate tag strings. + */ + private static Set getTagsFromArgs(String tagArguments) { + // no tags + if (tagArguments.isEmpty()) { + return Collections.emptySet(); + } + + // replace first delimiter prefix, then split + final Collection tagStrings = Arrays.asList(tagArguments.split(" ")); + return new HashSet<>(tagStrings); + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + /** + * Parses arguments in the context of the delete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareDelete(String args) { + + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + } + + return new DeleteCommand(index.get()); + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + + /** + * Parses arguments in the context of the select task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareSelect(String args) { + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE)); + } + + return new SelectCommand(index.get()); + } + + /** + * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index. + * Returns an {@code Optional.empty()} otherwise. + */ + private Optional parseIndex(String command) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim()); + if (!matcher.matches()) { + return Optional.empty(); + } + + String index = matcher.group("targetIndex"); + if(!StringUtil.isUnsignedInteger(index)){ + return Optional.empty(); + } + return Optional.of(Integer.parseInt(index)); + + } + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + /** + * Parses arguments in the context of the find task command. + * + * @param args full command args string + * @return the prepared command + */ + +``` +###### /seedu/gtd/logic/parser/Parser.java +``` java + +private Command prepareList(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + //String preprocessedArgs = " " + appendEnd(args.trim()); + return new ListCommand(args); +} + + /** + * Parses arguments in the context of the help command. + * + * @param args full command args string + * @return the prepared command + */ +``` +###### /seedu/gtd/MainApp.java +``` java +public class MainApp extends Application { + private static final Logger logger = LogsCenter.getLogger(MainApp.class); + + public static final Version VERSION = new Version(1, 0, 0, true); + + protected Ui ui; + protected Logic logic; + protected Storage storage; + protected Model model; + protected Config config; + protected UserPrefs userPrefs; + + public MainApp() {} + + @Override + public void init() throws Exception { + logger.info("=============================[ Initializing TaskList ]==========================="); + super.init(); + + config = initConfig(getApplicationParameter("config")); + storage = new StorageManager(config.getAddressBookFilePath(), config.getUserPrefsFilePath()); + + userPrefs = initPrefs(config); + + initLogging(config); + + model = initModelManager(storage, userPrefs); + + logic = new LogicManager(model, storage); + + ui = new UiManager(logic, config, userPrefs); + + initEventsCenter(); + } + + private String getApplicationParameter(String parameterName){ + Map applicationParameters = getParameters().getNamed(); + return applicationParameters.get(parameterName); + } + + private Model initModelManager(Storage storage, UserPrefs userPrefs) { + Optional addressBookOptional; + ReadOnlyAddressBook initialData; + try { + addressBookOptional = storage.readAddressBook(); + if(!addressBookOptional.isPresent()){ + logger.info("Data file not found. Will be starting with an empty TaskList"); + } + initialData = addressBookOptional.orElse(new AddressBook()); + } catch (DataConversionException e) { + logger.warning("Data file not in the correct format. Will be starting with an empty TaskList"); + initialData = new AddressBook(); + } catch (IOException e) { + logger.warning("Problem while reading from the file. . Will be starting with an empty TaskList"); + initialData = new AddressBook(); + } + + return new ModelManager(initialData, userPrefs); + } + + private void initLogging(Config config) { + LogsCenter.init(config); + } + + protected Config initConfig(String configFilePath) { + Config initializedConfig; + String configFilePathUsed; + + configFilePathUsed = Config.DEFAULT_CONFIG_FILE; + + if(configFilePath != null) { + logger.info("Custom Config file specified " + configFilePath); + configFilePathUsed = configFilePath; + } + + logger.info("Using config file : " + configFilePathUsed); + + try { + Optional configOptional = ConfigUtil.readConfig(configFilePathUsed); + initializedConfig = configOptional.orElse(new Config()); + } catch (DataConversionException e) { + logger.warning("Config file at " + configFilePathUsed + " is not in the correct format. " + + "Using default config properties"); + initializedConfig = new Config(); + } + + //Update config file in case it was missing to begin with or there are new/unused fields + try { + ConfigUtil.saveConfig(initializedConfig, configFilePathUsed); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + return initializedConfig; + } + + protected UserPrefs initPrefs(Config config) { + assert config != null; + + String prefsFilePath = config.getUserPrefsFilePath(); + logger.info("Using prefs file : " + prefsFilePath); + + UserPrefs initializedPrefs; + try { + Optional prefsOptional = storage.readUserPrefs(); + initializedPrefs = prefsOptional.orElse(new UserPrefs()); + } catch (DataConversionException e) { + logger.warning("UserPrefs file at " + prefsFilePath + " is not in the correct format. " + + "Using default user prefs"); + initializedPrefs = new UserPrefs(); + } catch (IOException e) { + logger.warning("Problem while reading from the file. . Will be starting with an empty TaskList"); + initializedPrefs = new UserPrefs(); + } + + //Update prefs file in case it was missing to begin with or there are new/unused fields + try { + storage.saveUserPrefs(initializedPrefs); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + + return initializedPrefs; + } + + private void initEventsCenter() { + EventsCenter.getInstance().registerHandler(this); + } + + @Override + public void start(Stage primaryStage) { + logger.info("Starting TaskList " + MainApp.VERSION); + ui.start(primaryStage); + } + + @Override + public void stop() { + logger.info("============================ [ Stopping Task List ] ============================="); + ui.stop(); + try { + storage.saveUserPrefs(userPrefs); + } catch (IOException e) { + logger.severe("Failed to save preferences " + StringUtil.getDetails(e)); + } + Platform.exit(); + System.exit(0); + } + + @Subscribe + public void handleExitAppRequestEvent(ExitAppRequestEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + this.stop(); + } + + public static void main(String[] args) { + launch(args); + } +} +``` +###### /seedu/gtd/model/AddressBook.java +``` java + private final UniqueTaskList tasks; + private final UniqueTagList tags; + + { + tasks = new UniqueTaskList(); + tags = new UniqueTagList(); + } + + public AddressBook() {} + + /** + * Tasks and Tags are copied into this addressbook + */ + public AddressBook(ReadOnlyAddressBook toBeCopied) { + this(toBeCopied.getUniqueTaskList(), toBeCopied.getUniqueTagList()); + } + + /** + * Tasks and Tags are copied into this addressbook + */ + public AddressBook(UniqueTaskList tasks, UniqueTagList tags) { + resetData(tasks.getInternalList(), tags.getInternalList()); + } + + public static ReadOnlyAddressBook getEmptyAddressBook() { + return new AddressBook(); + } + +``` +###### /seedu/gtd/model/AddressBook.java +``` java + //Reused config saving + configFilePathUsed = Config.DEFAULT_CONFIG_FILE; + try { + Optional configOptional = ConfigUtil.readConfig(configFilePathUsed); + changedConfig = configOptional.orElse(new Config()); + } catch (DataConversionException e) { + changedConfig = new Config(); + } + + changedConfig.setAddressBookFilePath(newFilePath); + System.out.println("Saved to " + newFilePath); + +``` +###### /seedu/gtd/model/AddressBook.java +``` java +//// list overwrite operations + + public ObservableList getTasks() { + return tasks.getInternalList(); + } + + public void setTasks(List tasks) { + this.tasks.getInternalList().setAll(tasks); + } + + public void setTags(Collection tags) { + this.tags.getInternalList().setAll(tags); + } + + public void resetData(Collection newTasks, Collection newTags) { + setTasks(newTasks.stream().map(Task::new).collect(Collectors.toList())); + setTags(newTags); + } + + public void resetData(ReadOnlyAddressBook newData) { + resetData(newData.getTaskList(), newData.getTagList()); + } + +//// task-level operations + + /** + * Adds a task to the address book. + * Also checks the new task's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the task to point to those in {@link #tags}. + * + * @throws UniqueTaskList.DuplicateTaskException if an equivalent task already exists. + */ + public void addTask(Task t) throws UniqueTaskList.DuplicateTaskException { + syncTagsWithMasterList(t); + tasks.add(t); + } + +``` +###### /seedu/gtd/model/AddressBook.java +``` java + /** + * Ensures that every tag in this task: + * - exists in the master list {@link #tags} + * - points to a Tag object in the master list + */ + private void syncTagsWithMasterList(Task t) { + final UniqueTagList taskTags = t.getTags(); + tags.mergeFrom(taskTags); + + // Create map with values = tag object references in the master list + final Map masterTagObjects = new HashMap<>(); + for (Tag tag : tags) { + masterTagObjects.put(tag, tag); + } + + // Rebuild the list of task tags using references from the master list + final Set commonTagReferences = new HashSet<>(); + for (Tag tag : taskTags) { + commonTagReferences.add(masterTagObjects.get(tag)); + } + t.setTags(new UniqueTagList(commonTagReferences)); + } + + public boolean removeTask(ReadOnlyTask key) throws UniqueTaskList.TaskNotFoundException { + if (tasks.remove(key)) { + return true; + } else { + throw new UniqueTaskList.TaskNotFoundException(); + } + } + + public void doneTask(int index, Task target) throws TaskNotFoundException { + tasks.done(index, target); + } + +//// tag-level operations + + public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { + tags.add(t); + } + +//// util methods + + @Override + public String toString() { + return tasks.getInternalList().size() + " tasks, " + tags.getInternalList().size() + " tags"; + // TODO: refine later + } + + @Override + public List getTaskList() { + return Collections.unmodifiableList(tasks.getInternalList()); + } + + @Override + public List getTagList() { + return Collections.unmodifiableList(tags.getInternalList()); + } + + @Override + public UniqueTaskList getUniqueTaskList() { + return this.tasks; + } + + @Override + public UniqueTagList getUniqueTagList() { + return this.tags; + } + + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddressBook // instanceof handles nulls + && this.tasks.equals(((AddressBook) other).tasks) + && this.tags.equals(((AddressBook) other).tags)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(tasks, tags); + } +} +``` +###### /seedu/gtd/model/ModelManager.java +``` java + + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private AddressBook addressBook; + private final FilteredList filteredTasks; + private Stack previousAddressBook; + + /** + * Initializes a ModelManager with the given AddressBook + * AddressBook and its variables should not be null + */ + public ModelManager(AddressBook src, UserPrefs userPrefs) { + super(); + assert src != null; + assert userPrefs != null; + + logger.fine("Initializing with address book: " + src + " and user prefs " + userPrefs); + + addressBook = new AddressBook(src); + filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new Stack(); + previousAddressBook.push(new AddressBook(addressBook)); + } + + public ModelManager() { + this(new AddressBook(), new UserPrefs()); + } + + public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { + addressBook = new AddressBook(initialData); + filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new Stack(); + previousAddressBook.push(new AddressBook(addressBook)); + } + + private void resetData(ReadOnlyAddressBook newData) { + addressBook.resetData(newData); + indicateAddressBookChanged(); + } + + @Override + public ReadOnlyAddressBook getAddressBook() { + return addressBook; + } + + /** Raises an event to indicate the model has changed */ + private void indicateAddressBookChanged() { + raise(new AddressBookChangedEvent(addressBook)); + } + + private void savePreviousAddressBook() { + previousAddressBook.push(new AddressBook(addressBook)); + } + + @Override + public boolean undoAddressBookChange() { + if(previousAddressBook.isEmpty()) { + return false; + } + else{ + resetData(previousAddressBook.pop()); + return true; + } + } + + @Override + public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.removeTask(target); + indicateAddressBookChanged(); + } + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + + @Override + public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskException { + savePreviousAddressBook(); + addressBook.addTask(task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + //=========== Filtered Task List Accessors =============================================================== + + @Override + public UnmodifiableObservableList getFilteredTaskList() { + return new UnmodifiableObservableList<>(filteredTasks); + } + +``` +###### /seedu/gtd/model/ModelManager.java +``` java + interface Expression { + boolean satisfies(ReadOnlyTask task); + String toString(); + } + + private class PredicateExpression implements Expression { + + private final Qualifier qualifier; + + PredicateExpression(Qualifier qualifier) { + this.qualifier = qualifier; + } + + @Override + public boolean satisfies(ReadOnlyTask task) { + return qualifier.run(task); + } + + @Override + public String toString() { + return qualifier.toString(); + } + } + + interface Qualifier { + boolean run(ReadOnlyTask task); + String toString(); + } + + private class NameQualifier implements Qualifier { + protected Set keywordSet; + + NameQualifier(Set keywordSet) { + this.keywordSet = keywordSet; + } + + @Override + public boolean run(ReadOnlyTask task) { + return keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); + } + + @Override + public String toString() { + return "name=" + String.join(", ", keywordSet); + } + } + +``` +###### /seedu/gtd/model/task/UniqueTaskList.java +``` java + /** + * Signals that an operation would have violated the 'no duplicates' property of the list. + */ + public static class DuplicateTaskException extends DuplicateDataException { + protected DuplicateTaskException() { + super("Operation would result in duplicate tasks"); + } + } + + /** + * Signals that an operation targeting a specified task in the list would fail because + * there is no such matching task in the list. + */ + public static class TaskNotFoundException extends Exception {} + + private final ObservableList internalList = FXCollections.observableArrayList(); + + /** + * Constructs empty TaskList. + */ + public UniqueTaskList() {} + + /** + * Returns true if the list contains an equivalent task as the given argument. + */ + public boolean contains(ReadOnlyTask toCheck) { + assert toCheck != null; + return internalList.contains(toCheck); + } + + /** + * Adds a task to the list. + * + * @throws DuplicateTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(Task toAdd) throws DuplicateTaskException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateTaskException(); + } + internalList.add(toAdd); + } + +``` +###### /seedu/gtd/model/task/UniqueTaskList.java +``` java + /** + * Removes the equivalent task from the list. + * + * @throws TaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyTask toRemove) throws TaskNotFoundException { + assert toRemove != null; + final boolean taskFoundAndDeleted = internalList.remove(toRemove); + if (!taskFoundAndDeleted) { + throw new TaskNotFoundException(); + } + return taskFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueTaskList // instanceof handles nulls + && this.internalList.equals( + ((UniqueTaskList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } +} +``` +###### /seedu/gtd/ui/BrowserPanel.java +``` java + /** + * Frees resources allocated to the browser. + */ + public void freeResources() { + browser = null; + } + +} +``` +###### /seedu/gtd/ui/MainWindow.java +``` java + private static final String FXML = "MainWindow.fxml"; + public static final int MIN_HEIGHT = 768; + public static final int MIN_WIDTH = 1024; + + private Logic logic; + + // Independent Ui parts residing in this Ui container + private BrowserPanel browserPanel; + private TaskListPanel taskListPanel; + private ResultDisplay resultDisplay; + private StatusBarFooter statusBarFooter; + private CommandBox commandBox; + private Config config; + private UserPrefs userPrefs; + + // Handles to elements of this Ui container + private VBox rootLayout; + private Scene scene; + + private String addressBookName; + + @FXML + private AnchorPane browserPlaceholder; + + @FXML + private AnchorPane commandBoxPlaceholder; + + @FXML + private MenuItem helpMenuItem; + + @FXML + private AnchorPane taskListPanelPlaceholder; + + @FXML + private AnchorPane resultDisplayPlaceholder; + + @FXML + private AnchorPane statusbarPlaceholder; + + + public MainWindow() { + super(); + } + + @Override + public void setNode(Node node) { + rootLayout = (VBox) node; + } + + @Override + public String getFxmlPath() { + return FXML; + } + + public static MainWindow load(Stage primaryStage, Config config, UserPrefs prefs, Logic logic) { + + MainWindow mainWindow = UiPartLoader.loadUiPart(primaryStage, new MainWindow()); + mainWindow.configure(config.getAppTitle(), config.getAddressBookName(), config, prefs, logic); + return mainWindow; + } + + private void configure(String appTitle, String addressBookName, Config config, UserPrefs prefs, + Logic logic) { + + //Set dependencies + this.logic = logic; + this.addressBookName = addressBookName; + this.config = config; + this.userPrefs = prefs; + + //Configure the UI + setTitle(appTitle); + setIcon(ICON); + setWindowMinSize(); + setWindowDefaultSize(prefs); + scene = new Scene(rootLayout); + primaryStage.setScene(scene); + + setAccelerators(); + } + + private void setAccelerators() { + helpMenuItem.setAccelerator(KeyCombination.valueOf("F1")); + } + + void fillInnerParts() { + browserPanel = BrowserPanel.load(getBrowserPlaceholder()); + browserPanel.loadPage("https://calendar.google.com"); + taskListPanel = TaskListPanel.load(primaryStage, getTaskListPlaceholder(), logic.getFilteredTaskList()); + resultDisplay = ResultDisplay.load(primaryStage, getResultDisplayPlaceholder()); + statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getAddressBookFilePath()); + commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic); + } + + private AnchorPane getBrowserPlaceholder() { + return browserPlaceholder; + } + + private AnchorPane getCommandBoxPlaceholder() { + return commandBoxPlaceholder; + } + + private AnchorPane getStatusbarPlaceholder() { + return statusbarPlaceholder; + } + + private AnchorPane getResultDisplayPlaceholder() { + return resultDisplayPlaceholder; + } + + public AnchorPane getTaskListPlaceholder() { + return taskListPanelPlaceholder; + } + + public void hide() { + primaryStage.hide(); + } + + private void setTitle(String appTitle) { + primaryStage.setTitle(appTitle); + } + + /** + * Sets the default size based on user preferences. + */ + protected void setWindowDefaultSize(UserPrefs prefs) { + primaryStage.setHeight(prefs.getGuiSettings().getWindowHeight()); + primaryStage.setWidth(prefs.getGuiSettings().getWindowWidth()); + if (prefs.getGuiSettings().getWindowCoordinates() != null) { + primaryStage.setX(prefs.getGuiSettings().getWindowCoordinates().getX()); + primaryStage.setY(prefs.getGuiSettings().getWindowCoordinates().getY()); + } + } + + private void setWindowMinSize() { + primaryStage.setMinHeight(MIN_HEIGHT); + primaryStage.setMinWidth(MIN_WIDTH); + } + + /** + * Returns the current size and the position of the main Window. + */ + public GuiSettings getCurrentGuiSetting() { + return new GuiSettings(primaryStage.getWidth(), primaryStage.getHeight(), + (int) primaryStage.getX(), (int) primaryStage.getY()); + } + + @FXML + public void handleHelp() { + HelpWindow helpWindow = HelpWindow.load(primaryStage); + helpWindow.show(); + } + + public void show() { + primaryStage.show(); + } + + /** + * Closes the application. + */ + @FXML + private void handleExit() { + raise(new ExitAppRequestEvent()); + } + +``` +###### /seedu/gtd/ui/MainWindow.java +``` java + public TaskListPanel getTaskListPanel() { + return this.taskListPanel; + } + + public void loadTaskPage(ReadOnlyTask task) { + browserPanel.loadTaskPage(task); + } + + public void releaseResources() { + browserPanel.freeResources(); + } +} +``` +###### /seedu/gtd/ui/UiManager.java +``` java + private Logic logic; + private Config config; + private UserPrefs prefs; + private MainWindow mainWindow; + + public UiManager(Logic logic, Config config, UserPrefs prefs) { + super(); + this.logic = logic; + this.config = config; + this.prefs = prefs; + } + + @Override + public void start(Stage primaryStage) { + logger.info("Starting UI..."); + primaryStage.setTitle(config.getAppTitle()); + + //Set the application icon. + primaryStage.getIcons().add(getImage(ICON_APPLICATION)); + + try { + mainWindow = MainWindow.load(primaryStage, config, prefs, logic); + mainWindow.show(); //This should be called before creating other UI parts + mainWindow.fillInnerParts(); + + } catch (Throwable e) { + logger.severe(StringUtil.getDetails(e)); + showFatalErrorDialogAndShutdown("Fatal error during initializing", e); + } + } + + @Override + public void stop() { + prefs.updateLastUsedGuiSetting(mainWindow.getCurrentGuiSetting()); + mainWindow.hide(); + mainWindow.releaseResources(); + } + + private void showFileOperationAlertAndWait(String description, String details, Throwable cause) { + final String content = details + ":\n" + cause.toString(); + showAlertDialogAndWait(AlertType.ERROR, "File Op Error", description, content); + } + + private Image getImage(String imagePath) { + return new Image(MainApp.class.getResourceAsStream(imagePath)); + } + + void showAlertDialogAndWait(Alert.AlertType type, String title, String headerText, String contentText) { + showAlertDialogAndWait(mainWindow.getPrimaryStage(), type, title, headerText, contentText); + } + + private static void showAlertDialogAndWait(Stage owner, AlertType type, String title, String headerText, + String contentText) { + final Alert alert = new Alert(type); + alert.getDialogPane().getStylesheets().add("view/DarkTheme.css"); + alert.initOwner(owner); + alert.setTitle(title); + alert.setHeaderText(headerText); + alert.setContentText(contentText); + + alert.showAndWait(); + } + + private void showFatalErrorDialogAndShutdown(String title, Throwable e) { + logger.severe(title + " " + e.getMessage() + StringUtil.getDetails(e)); + showAlertDialogAndWait(Alert.AlertType.ERROR, title, e.getMessage(), e.toString()); + Platform.exit(); + System.exit(1); + } + + //==================== Event Handling Code ================================================================= + + @Subscribe + private void handleDataSavingExceptionEvent(DataSavingExceptionEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + showFileOperationAlertAndWait("Could not save data", "Could not save data to file", event.exception); + } + + @Subscribe + private void handleShowHelpEvent(ShowHelpRequestEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + mainWindow.handleHelp(); + } + + @Subscribe + private void handleJumpToListRequestEvent(JumpToListRequestEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + mainWindow.getTaskListPanel().scrollTo(event.targetIndex); + } + + @Subscribe + private void handleTaskPanelSelectionChangedEvent(TaskPanelSelectionChangedEvent event){ + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + mainWindow.loadTaskPage(event.getNewSelection()); + } + +} +``` diff --git a/collated/test/A0130677A.md b/collated/test/A0130677A.md new file mode 100644 index 000000000000..125503e54835 --- /dev/null +++ b/collated/test/A0130677A.md @@ -0,0 +1,262 @@ +# A0130677A +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + @Test + public void execute_add_invalidStartEndDate() throws Exception { + assertCommandBehavior( + "add complete tutorial s/tomorrow d/yesterday a/valid, address p/1", START_END_DATE_INVALID_COMMAND_FORMAT); + } + + @Test + public void execute_add_floatingTask() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.floatingTask(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(toBeAdded); + + // execute command and verify result + assertCommandBehavior(helper.generateAddFloatingTask(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, toBeAdded), + expectedAB, + expectedAB.getTaskList()); + } + + @Test + public void execute_add_flexibleTaskData() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.fullTask(); + Task dateChanged = helper.fullTaskChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(dateChanged); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommandInRandomOrder(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, dateChanged), + expectedAB, + expectedAB.getTaskList()); + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + @Test + public void execute_add_optional_successful() throws Exception { + + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task intendedResult = helper.optionalAddressDateChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(intendedResult); + String optionalAddressCmd = "add clean room d/noon p/3 t/tag1"; + + assertCommandBehavior(optionalAddressCmd, + String.format(AddCommand.MESSAGE_SUCCESS, intendedResult), + expectedAB, + expectedAB.getTaskList()); + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + @Test + public void execute_done_task() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task taskDone = helper.fullTaskDone(); + List expectedTasks = helper.generateTaskList(taskDone); + AddressBook expectedAB = helper.generateAddressBook(expectedTasks); + model.addTask(taskDone); + + // execute command and verify result + assertCommandBehavior("done 1", + String.format(DoneCommand.MESSAGE_DONE_TASK_SUCCESS, taskDone), + expectedAB, + expectedAB.getTaskList()); + } + +// @Test +// public void execute_list_done_showsDoneTasks() throws Exception { +// // prepare expectations +// TestDataHelper helper = new TestDataHelper(); +// Task toBeDone = helper.fullTask(); +// Task taskDone = helper.fullTaskDone(); +// List expectedTasks = helper.generateTaskList(taskDone); +// AddressBook expectedAB = helper.generateAddressBook(expectedTasks); +// List expectedList = expectedAB.getTaskList(); +// +// // prepare address book state +// model.addTask(taskDone); +// +// assertCommandBehavior("list done", +// ListCommand.MESSAGE_SUCCESS_LIST_DONE, +// expectedAB, +// expectedList); +// } +// +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + @Test + public void execute_find_by_attributes() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget = helper.fullTask(); + Task p = helper.floatingTask(); + + List twoTasks = helper.generateTaskList(pTarget, p); + AddressBook expectedAB = helper.generateAddressBook(twoTasks); + List expectedList = helper.generateTaskList(pTarget); + helper.addToModel(model, twoTasks); + + assertCommandBehavior("find p/4", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + /** + * A utility class to generate test data. + */ + class TestDataHelper{ + + Task fullTask() throws Exception { + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate("morning"); + DueDate privateDueDate = new DueDate("noon"); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("4"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags); + } + + Task fullTaskChanged() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate(formattedStartDate); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("4"); + boolean isDone = false; + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags, isDone); + } + + Task fullTaskDone() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate(formattedStartDate); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("4"); + boolean isDone = true; + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags, isDone); + } + + Task floatingTask() throws Exception { + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate("nil"); + DueDate privateDueDate = new DueDate("nil"); + Address address = new Address("nil"); + Priority privatePriority = new Priority("1"); + UniqueTagList tags = new UniqueTagList(); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags); + } + + Task optionalAddressDateChanged() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + Name name = new Name("clean room"); + DueDate startDate = new DueDate(formattedStartDate); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("none"); + Priority privatePriority = new Priority("3"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags); + } + + /** + * Generates a valid task using the given seed. + * Running this function with the same parameter values guarantees the returned task will have the same state. + * Each unique seed will generate a unique Task object. + * + * @param seed used to generate the task data field values + */ + Task generateTask(int seed) throws Exception { + return new Task( + new Name("Task " + seed), + new DueDate("" + Math.abs(seed)), + new DueDate("" + Math.abs(seed)), + new Address(seed + ", -address"), + new Priority("1 "), + new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1))) + ); + } + + /** Generates the correct add command based on the task given */ + String generateAddCommand(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + + cmd.append(p.getName().toString()); + cmd.append(" s/").append(p.getStartDate()); + cmd.append(" d/").append(p.getDueDate()); + cmd.append(" a/").append(p.getAddress()); + cmd.append(" p/").append(p.getPriority()); + + UniqueTagList tags = p.getTags(); + for(Tag t: tags){ + cmd.append(" t/").append(t.tagName); + } + + return cmd.toString(); + } + + String generateAddCommandInRandomOrder(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + + cmd.append(p.getName().toString()); + cmd.append(" p/").append(p.getPriority()); + cmd.append(" a/").append(p.getAddress()); + cmd.append(" s/").append(p.getStartDate()); + cmd.append(" d/").append(p.getDueDate()); + + UniqueTagList tags = p.getTags(); + for(Tag t: tags){ + cmd.append(" t/").append(t.tagName); + } + + return cmd.toString(); + } + + String generateAddFloatingTask(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + cmd.append(p.getName().toString()); + return cmd.toString(); + } + +``` diff --git a/collated/test/A0146130W.md b/collated/test/A0146130W.md new file mode 100644 index 000000000000..c49d2f786985 --- /dev/null +++ b/collated/test/A0146130W.md @@ -0,0 +1,264 @@ +# A0146130W +###### /guitests/EditCommandTest.java +``` java + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.EditCommand.MESSAGE_EDIT_TASK_SUCCESS; + +public class EditCommandTest extends AddressBookGuiTest { + + @Test + public void edit() { + + //edit the priority of the first task + TestTask[] currentList = td.getTypicalTasks(); + int targetIndex = 1; + String change = "p/4"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the dueDate of the last in the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + targetIndex = currentList.length; + change = "d/2"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the name task from the middle of the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + targetIndex = currentList.length/2; + change = "Cook lunch for friends"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the address task from the middle of the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + change = "a/Little India"; + assertEditSuccess(targetIndex, change, currentList); + + /* + //edit everything at once + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + change = "Cook friends for lunch d/midnight a/SMU p/5"; + String change1 = "Cook friends for lunch"; + String change2 = "d/midnight"; + String change3 = "a/SMU"; + String change4 = "p/5"; + String[] changes = {change1, change2, change3, change4}; + assertMultipleEditSuccess(targetIndex, change, currentList, changes); + */ + + //invalid index + commandBox.runCommand("edit " + currentList.length + 1 + " Invalid"); + assertResultMessage("The task index provided is invalid"); + + } + + /** + * Runs the edit command to edit the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to edit the first task in the list, 1 should be given as the target index. + * @param currentList A copy of the current list of tasks (before editing) + * @param change: contains detail with appropriate prefix that the user wants to edit into a task with index targetIndexOneIndexed. + * + */ + private void assertEditSuccess(int targetIndexOneIndexed, String change, final TestTask[] currentList) { + TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestTask[] expectedRemainder = TestUtil.editTaskInList(currentList, targetIndexOneIndexed, change, taskToEdit); + commandBox.runCommand("edit " + targetIndexOneIndexed + " " + change); + + assertTrue(taskListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_EDIT_TASK_SUCCESS, expectedRemainder[targetIndexOneIndexed-1])); + } + + /* + private void assertMultipleEditSuccess(int targetIndexOneIndexed, String change, TestTask[] currentList, String[] changeArr) { + TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + + for(String c: changeArr) { + currentList = TestUtil.editTaskInList(currentList, targetIndexOneIndexed, c, taskToEdit); + } + TestTask[] expectedRemainder = currentList; + + commandBox.runCommand("edit " + targetIndexOneIndexed + " " + change); + + assertTrue(taskListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_EDIT_TASK_SUCCESS, expectedRemainder[targetIndexOneIndexed-1])); + } + */ +} +``` +###### /guitests/UndoCommandTest.java +``` java + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_SUCCESS; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_UNDO_LIMIT_REACHED; + +import java.util.Stack;; + +public class UndoCommandTest extends AddressBookGuiTest { + + @Test + public void undo() { + + //undo the addition of the first task + TestTask[] currentList = td.getTypicalTasks(); + Stack previousList = new Stack(); + previousList.push(currentList); + commandBox.runCommand(td.george.getAddCommand()); + assertUndoSuccess(previousList.pop()); + + //undo editing the dueDate of the last task in the list + int targetIndex = currentList.length; + String change = "d/2"; + previousList.push(currentList); + commandBox.runCommand("edit " + targetIndex + " " + change); + assertUndoSuccess(previousList.pop()); + + //undo deleting a task from the middle of the list + targetIndex = currentList.length/2; + previousList.push(currentList); + commandBox.runCommand("delete " + targetIndex); + assertUndoSuccess(previousList.pop()); + + //undo clearing list + previousList.push(currentList); + commandBox.runCommand("clear"); + assertUndoSuccess(previousList.pop()); + + //undo marking the middle task as done + previousList.push(currentList); + commandBox.runCommand("done " + targetIndex); + assertUndoSuccess(previousList.pop()); + + /* + //undo multiple times + previousList.push(currentList); + commandBox.runCommand("edit " + targetIndex + " " + change); + previousList.push(currentList); + commandBox.runCommand(td.george.getAddCommand()); + previousList.push(currentList); + commandBox.runCommand("delete " + targetIndex); + previousList.push(currentList); + commandBox.runCommand("done " + targetIndex); + previousList.push(currentList); + commandBox.runCommand("clear"); + assertMultipleUndoSuccess(previousList); + */ + } + + /** + * Runs the undo command to undo the last change to the task list + */ + private void assertUndoSuccess(final TestTask[] previousList) { + commandBox.runCommand("undo"); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(previousList)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + + private void assertMultipleUndoSuccess(final Stack previousList) { + + //run undo multiple times and verify list each time + for(int i=1; i < previousList.size(); i++) { + commandBox.runCommand("undo"); + assertTrue(taskListPanel.isListMatching(previousList.pop())); + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + + //verify that the undo limit message is shown when undo limit is reached + commandBox.runCommand("undo"); + assertResultMessage(String.format(MESSAGE_UNDO_LIMIT_REACHED)); + } + +} +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + /** Generates the correct add command based on the task given */ + String generateEditCommand(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("edit "); + cmd.append(" d/").append(p.getDueDate()); + + return cmd.toString(); + } +``` +###### /seedu/gtd/testutil/TestUtil.java +``` java + + /** + * Edits a task in the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. + * @throws IllegalValueException + */ + public static TestTask[] editTaskInList(final TestTask[] tasks, int index, String change, TestTask taskToEdit) { + List listOfTasks = asList(tasks); + TestTask taskEditted; + try { + taskEditted = TestUtilParser.editTask(taskToEdit, change); + } catch (IllegalValueException e) { + taskEditted = taskToEdit; + e.printStackTrace(); + } + listOfTasks.set(index-1, taskEditted); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + +``` +###### /seedu/gtd/testutil/TestUtilParser.java +``` java + +package seedu.gtd.testutil; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.logic.parser.DateNaturalLanguageProcessor; +import seedu.gtd.logic.parser.NaturalLanguageProcessor; +import seedu.gtd.model.task.Address; +import seedu.gtd.model.task.DueDate; +import seedu.gtd.model.task.Name; +import seedu.gtd.model.task.Priority; + +/** + * A utility class that parses tasks for test cases. + */ +public class TestUtilParser { + + public static TestTask editTask(TestTask task, String change) throws IllegalValueException { + + TestTask newTask = task; + String changeWithoutPrefix = removeDetailPrefix(change); + String changePrefix = change.substring(0, 2); + System.out.println("From TestUtil Parser: " + changePrefix + " " + changeWithoutPrefix); + + switch(change.substring(0, 2)) { + case "d/": newTask = new TestTask(task.getName(), task.getStartDate(), new DueDate(parseDueDate(changeWithoutPrefix)), task.getAddress(), task.getPriority(), task.getTags()); break; + case "a/": newTask = new TestTask(task.getName(), task.getStartDate(), task.getDueDate(), new Address(changeWithoutPrefix), task.getPriority(), task.getTags()); break; + case "p/": newTask = new TestTask(task.getName(), task.getStartDate(), task.getDueDate(), task.getAddress(), new Priority(changeWithoutPrefix), task.getTags()); break; + default: newTask = new TestTask(new Name(change), task.getStartDate(), task.getDueDate(), task.getAddress(), task.getPriority(), task.getTags()); + } + return newTask; + } + +``` diff --git a/collated/test/A0146130Wreused.md b/collated/test/A0146130Wreused.md new file mode 100644 index 000000000000..37a931aaa267 --- /dev/null +++ b/collated/test/A0146130Wreused.md @@ -0,0 +1,29 @@ +# A0146130Wreused +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + @Test + public void execute_help() throws Exception { + assertCommandBehavior("help", HelpCommand.MESSAGE_USAGE+"/n"+HelpCommand.SHOWING_HELP_MESSAGE); + assertTrue(helpShown); + assertCommandBehavior("help add", AddCommand.MESSAGE_USAGE); + assertCommandBehavior("help select", SelectCommand.MESSAGE_USAGE); + assertCommandBehavior("help delete", DeleteCommand.MESSAGE_USAGE); + assertCommandBehavior("help clear", ClearCommand.MESSAGE_USAGE); + assertCommandBehavior("help find", FindCommand.MESSAGE_USAGE); + assertCommandBehavior("help list", ListCommand.MESSAGE_USAGE); + assertCommandBehavior("help exit", ExitCommand.MESSAGE_USAGE); + } + +``` +###### /seedu/gtd/testutil/TestUtilParser.java +``` java + public static String parseDueDate(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.formatString(dueDateRaw); + } + + private static String removeDetailPrefix(String detailWithPrefix) { + return detailWithPrefix.substring(detailWithPrefix.indexOf('/') + 1); + } +} +``` diff --git a/collated/test/addressbooklevel4.md b/collated/test/addressbooklevel4.md new file mode 100644 index 000000000000..81137e5e1074 --- /dev/null +++ b/collated/test/addressbooklevel4.md @@ -0,0 +1,544 @@ +# addressbooklevel4 +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + /** + * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule + */ + @Rule + public TemporaryFolder saveFolder = new TemporaryFolder(); + + private Model model; + private Logic logic; + + //These are for checking the correctness of the events raised + private ReadOnlyAddressBook latestSavedAddressBook; + private boolean helpShown; + private int targetedJumpIndex; + + @Subscribe + private void handleLocalModelChangedEvent(AddressBookChangedEvent abce) { + latestSavedAddressBook = new AddressBook(abce.data); + } + + @Subscribe + private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) { + helpShown = true; + } + + @Subscribe + private void handleJumpToListRequestEvent(JumpToListRequestEvent je) { + targetedJumpIndex = je.targetIndex; + } + + @Before + public void setup() { + model = new ModelManager(); + String tempAddressBookFile = saveFolder.getRoot().getPath() + "TempAddressBook.xml"; + String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json"; + logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile)); + EventsCenter.getInstance().registerHandler(this); + + latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before. + helpShown = false; + targetedJumpIndex = -1; // non yet + } + + @After + public void teardown() { + EventsCenter.clearSubscribers(); + } + + @Test + public void execute_invalid() throws Exception { + String invalidCommand = " "; + assertCommandBehavior(invalidCommand, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + /** + * Executes the command and confirms that the result message is correct. + * Both the 'address book' and the 'last shown list' are expected to be empty. + * @see #assertCommandBehavior(String, String, ReadOnlyAddressBook, List) + */ + private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { + assertCommandBehavior(inputCommand, expectedMessage, new AddressBook(), Collections.emptyList()); + } + + /** + * Executes the command and confirms that the result message is correct and + * also confirms that the following three parts of the LogicManager object's state are as expected:
+ * - the internal address book data are same as those in the {@code expectedAddressBook}
+ * - the backing list shown by UI matches the {@code shownList}
+ * - {@code expectedAddressBook} was saved to the storage file.
+ */ + private void assertCommandBehavior(String inputCommand, String expectedMessage, + ReadOnlyAddressBook expectedAddressBook, + List expectedShownList) throws Exception { + + //Execute the command + CommandResult result = logic.execute(inputCommand); + System.out.println(inputCommand); + + //Confirm the ui display elements should contain the right data + System.out.println(result.feedbackToUser); + System.out.println(expectedMessage); + assertEquals(expectedMessage, result.feedbackToUser); + System.out.println("correct message"); + assertEquals(expectedShownList, model.getFilteredTaskList()); + System.out.println("correct data in UI"); + + //Confirm the state of data (saved and in-memory) is as expected + assertEquals(expectedAddressBook, model.getAddressBook()); + assertEquals(expectedAddressBook, latestSavedAddressBook); + } + + + @Test + public void execute_unknownCommandWord() throws Exception { + String unknownCommand = "uicfhmowqewca"; + assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND); + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + @Test + public void execute_exit() throws Exception { + assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT); + } + + @Test + public void execute_clear() throws Exception { + TestDataHelper helper = new TestDataHelper(); + model.addTask(helper.generateTask(1)); + model.addTask(helper.generateTask(2)); + model.addTask(helper.generateTask(3)); + + assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new AddressBook(), Collections.emptyList()); + } + + @Test + public void execute_add_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); + assertCommandBehavior( + "add ", expectedMessage); + } + + + @Test + public void execute_add_invalidTaskData() throws Exception { + assertCommandBehavior( + "add []\\[;] d/12345 a/valid, address p/1", Name.MESSAGE_NAME_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/not_numbers a/valid, address p/2", DueDate.MESSAGE_DUEDATE_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/12345 a/valid, address p/not_priority_numbers", Priority.MESSAGE_PRIORITY_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/12345 a/valid, address p/5 t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); + + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + @Test + public void execute_add_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.fullTask(); + Task dateChanged = helper.fullTaskChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(dateChanged); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, dateChanged), + expectedAB, + expectedAB.getTaskList()); + + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + @Test + public void execute_addDuplicate_notAllowed() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.fullTask(); + Task changedDate = helper.fullTaskChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(changedDate); + + // setup starting state + model.addTask(changedDate); // task already in internal address book + + // execute command and verify result + assertCommandBehavior( + helper.generateAddCommand(toBeAdded), + AddCommand.MESSAGE_DUPLICATE_TASK, + expectedAB, + expectedAB.getTaskList()); + + } + + /* + @Test + public void execute_edit_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeEdited = helper.adam(); + AddressBook expectedAB = helper.generateAddressBook(2); + expectedAB.editTask(1, toBeEdited); + + // execute command and verify result + assertCommandBehavior(helper.generateEditCommand(toBeEdited), + String.format(EditCommand.MESSAGE_EDIT_TASK_SUCCESS, toBeEdited), + expectedAB, + expectedAB.getTaskList()); + } + */ + + + @Test + public void execute_list_showsAllTasks() throws Exception { + // prepare expectations + TestDataHelper helper = new TestDataHelper(); + AddressBook expectedAB = helper.generateAddressBook(2); + List expectedList = expectedAB.getTaskList(); + + // prepare address book state + helper.addToModel(model, 2); + + assertCommandBehavior("list", + ListCommand.MESSAGE_SUCCESS_LIST, + expectedAB, + expectedList); + } + +``` +###### /seedu/gtd/testutil/TestUtil.java +``` java + + public static String LS = System.lineSeparator(); + + public static void assertThrows(Class expected, Runnable executable) { + try { + executable.run(); + } + catch (Throwable actualException) { + if (!actualException.getClass().isAssignableFrom(expected)) { + String message = String.format("Expected thrown: %s, actual: %s", expected.getName(), + actualException.getClass().getName()); + throw new AssertionFailedError(message); + } else return; + } + throw new AssertionFailedError( + String.format("Expected %s to be thrown, but nothing was thrown.", expected.getName())); + } + + /** + * Folder used for temp files created during testing. Ignored by Git. + */ + public static String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); + + public static final Task[] sampleTaskData = getSampleTaskData(); + + private static Task[] getSampleTaskData() { + try { + return new Task[]{ + new Task(new Name("Ali Muster"), new DueDate("9482424"), new DueDate("9482424"), new Address("4th street"), new Priority("4"), new UniqueTagList()), + new Task(new Name("Boris Mueller"), new DueDate("9482424"), new DueDate("87249245"), new Address("81th street"), new Priority("3"), new UniqueTagList()), + new Task(new Name("Carl Kurz"), new DueDate("9482424"), new DueDate("95352563"), new Address("wall street"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Daniel Meier"), new DueDate("9482424"), new DueDate("87652533"), new Address("10th street"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Elle Meyer"), new DueDate("9482424"), new DueDate("9482224"), new Address("michegan ave"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Fiona Kunz"), new DueDate("9482424"), new DueDate("9482427"), new Address("little tokyo"), new Priority("1"), new UniqueTagList()), + new Task(new Name("George Best"), new DueDate("9482424"), new DueDate("9482442"), new Address("4th street"), new Priority("4"), new UniqueTagList()), + new Task(new Name("Hoon Meier"), new DueDate("9482424"), new DueDate("8482424"), new Address("little india"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Ida Mueller"), new DueDate("9482424"), new DueDate("8482131"), new Address("chicago ave"), new Priority("1"), new UniqueTagList()) + }; + } catch (IllegalValueException e) { + assert false; + //not possible + return null; + } + } + + public static final Tag[] sampleTagData = getSampleTagData(); + + private static Tag[] getSampleTagData() { + try { + return new Tag[]{ + new Tag("relatives"), + new Tag("friends") + }; + } catch (IllegalValueException e) { + assert false; + return null; + //not possible + } + } + + public static List generateSampleTaskData() { + return Arrays.asList(sampleTaskData); + } + + /** + * Appends the file name to the sandbox folder path. + * Creates the sandbox folder if it doesn't exist. + * @param fileName + * @return + */ + public static String getFilePathInSandboxFolder(String fileName) { + try { + FileUtil.createDirs(new File(SANDBOX_FOLDER)); + } catch (IOException e) { + throw new RuntimeException(e); + } + return SANDBOX_FOLDER + fileName; + } + + public static void createDataFileWithSampleData(String filePath) { + createDataFileWithData(generateSampleStorageAddressBook(), filePath); + } + + public static void createDataFileWithData(T data, String filePath) { + try { + File saveFileForTesting = new File(filePath); + FileUtil.createIfMissing(saveFileForTesting); + XmlUtil.saveDataToFile(saveFileForTesting, data); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String... s) { + createDataFileWithSampleData(TestApp.SAVE_LOCATION_FOR_TESTING); + } + + public static AddressBook generateEmptyAddressBook() { + return new AddressBook(new UniqueTaskList(), new UniqueTagList()); + } + + public static XmlSerializableAddressBook generateSampleStorageAddressBook() { + return new XmlSerializableAddressBook(generateEmptyAddressBook()); + } + + /** + * Tweaks the {@code keyCodeCombination} to resolve the {@code KeyCode.SHORTCUT} to their + * respective platform-specific keycodes + */ + public static KeyCode[] scrub(KeyCodeCombination keyCodeCombination) { + List keys = new ArrayList<>(); + if (keyCodeCombination.getAlt() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.ALT); + } + if (keyCodeCombination.getShift() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.SHIFT); + } + if (keyCodeCombination.getMeta() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.META); + } + if (keyCodeCombination.getControl() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.CONTROL); + } + keys.add(keyCodeCombination.getCode()); + return keys.toArray(new KeyCode[]{}); + } + + public static boolean isHeadlessEnvironment() { + String headlessProperty = System.getProperty("testfx.headless"); + return headlessProperty != null && headlessProperty.equals("true"); + } + + public static void captureScreenShot(String fileName) { + File file = GuiTest.captureScreenshot(); + try { + Files.copy(file, new File(fileName + ".png")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String descOnFail(Object... comparedObjects) { + return "Comparison failed \n" + + Arrays.asList(comparedObjects).stream() + .map(Object::toString) + .collect(Collectors.joining("\n")); + } + + public static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException{ + field.setAccessible(true); + // remove final modifier from field + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + // ~Modifier.FINAL is used to remove the final modifier from field so that its value is no longer + // final and can be changed + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + field.set(null, newValue); + } + + public static void initRuntime() throws TimeoutException { + FxToolkit.registerPrimaryStage(); + FxToolkit.hideStage(); + } + + public static void tearDownRuntime() throws Exception { + FxToolkit.cleanupStages(); + } + + /** + * Gets private method of a class + * Invoke the method using method.invoke(objectInstance, params...) + * + * Caveat: only find method declared in the current Class, not inherited from supertypes + */ + public static Method getPrivateMethod(Class objectClass, String methodName) throws NoSuchMethodException { + Method method = objectClass.getDeclaredMethod(methodName); + method.setAccessible(true); + return method; + } + + public static void renameFile(File file, String newFileName) { + try { + Files.copy(file, new File(newFileName)); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + + /** + * Gets mid point of a node relative to the screen. + * @param node + * @return + */ + public static Point2D getScreenMidPoint(Node node) { + double x = getScreenPos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; + double y = getScreenPos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; + return new Point2D(x,y); + } + + /** + * Gets mid point of a node relative to its scene. + * @param node + * @return + */ + public static Point2D getSceneMidPoint(Node node) { + double x = getScenePos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; + double y = getScenePos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; + return new Point2D(x,y); + } + + /** + * Gets the bound of the node relative to the parent scene. + * @param node + * @return + */ + public static Bounds getScenePos(Node node) { + return node.localToScene(node.getBoundsInLocal()); + } + + public static Bounds getScreenPos(Node node) { + return node.localToScreen(node.getBoundsInLocal()); + } + + public static double getSceneMaxX(Scene scene) { + return scene.getX() + scene.getWidth(); + } + + public static double getSceneMaxY(Scene scene) { + return scene.getX() + scene.getHeight(); + } + + public static Object getLastElement(List list) { + return list.get(list.size() - 1); + } + + /** + * Removes a subset from the list of tasks. + * @param tasks The list of tasks + * @param tasksToRemove The subset of tasks. + * @return The modified tasks after removal of the subset from tasks. + */ + public static TestTask[] removeTasksFromList(final TestTask[] tasks, TestTask... tasksToRemove) { + List listOfTasks = asList(tasks); + listOfTasks.removeAll(asList(tasksToRemove)); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + + + /** + * Returns a copy of the list with the task at specified index removed. + * @param list original list to copy from + * @param targetIndexInOneIndexedFormat e.g. if the first element to be removed, 1 should be given as index. + */ + public static TestTask[] removeTaskFromList(final TestTask[] list, int targetIndexInOneIndexedFormat) { + return removeTasksFromList(list, list[targetIndexInOneIndexedFormat-1]); + } + + /** + * Replaces tasks[i] with a task. + * @param tasks The array of tasks. + * @param task The replacement task + * @param index The index of the task to be replaced. + * @return + */ + public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task, int index) { + tasks[index] = task; + return tasks; + } + + /** + * Appends tasks to the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. + */ + public static TestTask[] addTasksToList(final TestTask[] tasks, TestTask... tasksToAdd) { + List listOfTasks = asList(tasks); + listOfTasks.addAll(asList(tasksToAdd)); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + +``` +###### /seedu/gtd/testutil/TestUtil.java +``` java + + private static List asList(T[] objs) { + List list = new ArrayList<>(); + for(T obj : objs) { + list.add(obj); + } + return list; + } + + public static boolean compareCardAndTask(TaskCardHandle card, ReadOnlyTask task) { + return card.isSameTask(task); + } + + public static Tag[] getTagList(String tags) { + + if (tags.equals("")) { + return new Tag[]{}; + } + + final String[] split = tags.split(", "); + + final List collect = Arrays.asList(split).stream().map(e -> { + try { + return new Tag(e.replaceFirst("Tag: ", "")); + } catch (IllegalValueException e1) { + //not possible + assert false; + return null; + } + }).collect(Collectors.toList()); + + return collect.toArray(new Tag[split.length]); + } + +} +``` diff --git a/collated/test/generated.md b/collated/test/generated.md new file mode 100644 index 000000000000..f87705a9bdf4 --- /dev/null +++ b/collated/test/generated.md @@ -0,0 +1,257 @@ +# generated +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { + assertCommandBehavior(commandWord , expectedMessage); //index missing + assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0 + assertCommandBehavior(commandWord + " not_a_number", expectedMessage); + } + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { + String expectedMessage = MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + TestDataHelper helper = new TestDataHelper(); + List taskList = helper.generateTaskList(2); + + // set AB state to 2 tasks + model.clearTaskList(); + for (Task p : taskList) { + model.addTask(p); + } + + assertCommandBehavior(commandWord + " 3", expectedMessage, model.getAddressBook(), taskList); + } + + @Test + public void execute_selectInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("select", expectedMessage); + } + + @Test + public void execute_selectIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("select"); + } + + @Test + public void execute_select_jumpsToCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeTasks = helper.generateTaskList(3); + + AddressBook expectedAB = helper.generateAddressBook(threeTasks); + helper.addToModel(model, threeTasks); + + assertCommandBehavior("select 2", + String.format(SelectCommand.MESSAGE_SELECT_TASK_SUCCESS, 2), + expectedAB, + expectedAB.getTaskList()); + assertEquals(1, targetedJumpIndex); + assertEquals(model.getFilteredTaskList().get(1), threeTasks.get(1)); + } + + + @Test + public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage); + } + + @Test + public void execute_deleteIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("delete"); + } + + @Test + public void execute_delete_removesCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeTasks = helper.generateTaskList(3); + + AddressBook expectedAB = helper.generateAddressBook(threeTasks); + expectedAB.removeTask(threeTasks.get(1)); + helper.addToModel(model, threeTasks); + + assertCommandBehavior("delete 2", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, threeTasks.get(1)), + expectedAB, + expectedAB.getTaskList()); + } + + + @Test + public void execute_find_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); + assertCommandBehavior("find ", expectedMessage); + } + + @Test + public void execute_find_onlyMatchesFullWordsInNames() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + Task pTarget2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + Task p1 = helper.generateTaskWithName("KE Y"); + Task p2 = helper.generateTaskWithName("KEYKEYKEY sduauo"); + + List fourTasks = helper.generateTaskList(p1, pTarget1, p2, pTarget2); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = helper.generateTaskList(pTarget1, pTarget2); + helper.addToModel(model, fourTasks); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + @Test + public void execute_find_isNotCaseSensitive() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task p1 = helper.generateTaskWithName("bla bla KEY bla"); + Task p2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + Task p3 = helper.generateTaskWithName("key key"); + Task p4 = helper.generateTaskWithName("KEy sduauo"); + + List fourTasks = helper.generateTaskList(p3, p1, p4, p2); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = fourTasks; + helper.addToModel(model, fourTasks); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + @Test + public void execute_find_matchesIfAnyKeywordPresent() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + Task pTarget2 = helper.generateTaskWithName("bla rAnDoM bla bceofeia"); + Task pTarget3 = helper.generateTaskWithName("key key"); + Task p1 = helper.generateTaskWithName("sduauo"); + + List fourTasks = helper.generateTaskList(pTarget1, p1, pTarget2, pTarget3); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = helper.generateTaskList(pTarget1, pTarget2, pTarget3); + helper.addToModel(model, fourTasks); + + String keywords = "key rAnDoM"; + TestFindHelper findhelper = new TestFindHelper(); + + assertCommandBehavior("find " + keywords, + String.format(findhelper.generateCorrectResultIfExactPhraseNotFound(keywords, expectedList.size())), + expectedAB, + expectedList); + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + + class TestFindHelper{ + + String generateCorrectResultIfExactPhraseNotFound(String keywords, int expectedListSize) { + String task_tasks = (expectedListSize == 1) ? "task" : "tasks"; + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + expectedListSize + " " + task_tasks + " containing the keywords entered instead."; + return MESSAGE_IF_EXACT_PHRASE_NOT_FOUND; + } + } + +``` +###### /seedu/gtd/logic/LogicManagerTest.java +``` java + /** + * Generates an AddressBook with auto-generated tasks. + */ + AddressBook generateAddressBook(int numGenerated) throws Exception{ + AddressBook addressBook = new AddressBook(); + addToAddressBook(addressBook, numGenerated); + return addressBook; + } + + /** + * Generates an AddressBook based on the list of Tasks given. + */ + AddressBook generateAddressBook(List tasks) throws Exception{ + AddressBook addressBook = new AddressBook(); + addToAddressBook(addressBook, tasks); + return addressBook; + } + + /** + * Adds auto-generated Task objects to the given AddressBook + * @param addressBook The AddressBook to which the Tasks will be added + */ + void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{ + addToAddressBook(addressBook, generateTaskList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given AddressBook + */ + void addToAddressBook(AddressBook addressBook, List tasksToAdd) throws Exception{ + for(Task p: tasksToAdd){ + addressBook.addTask(p); + } + } + + /** + * Adds auto-generated Task objects to the given model + * @param model The model to which the Tasks will be added + */ + void addToModel(Model model, int numGenerated) throws Exception{ + addToModel(model, generateTaskList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given model + */ + void addToModel(Model model, List tasksToAdd) throws Exception{ + for(Task p: tasksToAdd){ + model.addTask(p); + } + } + + /** + * Generates a list of Tasks based on the flags. + */ + List generateTaskList(int numGenerated) throws Exception{ + List tasks = new ArrayList<>(); + for(int i = 1; i <= numGenerated; i++){ + tasks.add(generateTask(i)); + } + return tasks; + } + + List generateTaskList(Task... tasks) { + return Arrays.asList(tasks); + } + + /** + * Generates a Task object with given name. Other fields will have some dummy values. + */ + Task generateTaskWithName(String name) throws Exception { + return new Task( + new Name(name), + new DueDate("3"), + new DueDate("1"), + new Address("House of 1"), + new Priority("1"), + new UniqueTagList(new Tag("tag")) + ); + } + } +} +``` diff --git a/config/findbugs/excludeFilter.xml b/config/findbugs/excludeFilter.xml index 03c15ae4cc81..69406bf4ab5e 100644 --- a/config/findbugs/excludeFilter.xml +++ b/config/findbugs/excludeFilter.xml @@ -6,7 +6,7 @@ - + diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 33df65bea583..c8763d2942c6 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -4,49 +4,73 @@ We are a team based in the [School of Computing, National University of Singapor ## Project Team -#### [Damith C. Rajapakse](http://www.comp.nus.edu.sg/~damithch)
-
-**Role**: Project Advisor +#### [Ravi Shwetha](http://github.com/ravishwetha) +
+* Components in charge of: [Storage and Testing](https://github.com/se-edu/addressbook-level4/blob/master/docs/DeveloperGuide.md#storage-component) +* Aspects/tools in charge of: Testing, Git +* Features implemented: + * [Basic undo and multiple undo](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#listing-all-persons--list) + * [Edit task](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#deleting-a-person--delete) + * [Find searches for exact keywords first](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#deleting-a-person--delete) + * [Natural language processing for dates using Natty API](https://github.com/se-edu/addressbook-level4/blob/master/docs/UserGuide.md#deleting-a-person--delete) +* Code written: [[functional code](A0146130W.md)][[test code](A0146130W.md)][[docs](A0146130W.md)] +* Other major contributions: + * Did the initial refactoring from Person model to Task model [[#133](https://github.com/se-edu/addressbook-level4/pull/152) ] + * Set up Coveralls and Collate + * Change browser to search task location on google maps + ----- -#### [Joshua Lee](http://github.com/lejolly) -
+#### [Tan Shao Yun](http://github.com/shaocloud) +
Role: Developer
-Responsibilities: UI +* Components in charge of: [UI, Design](https://github.com/CS2103AUG2016-F10-C3/main/blob/master/docs/DeveloperGuide.md#design) +* Features implemented: + * [Reordered UI](https://github.com/CS2103AUG2016-F10-C3/main/tree/master/src/main/resources/view) + * [UML Design](https://github.com/CS2103AUG2016-F10-C3/main/blob/master/docs/DeveloperGuide.md) +* Other major contributions: + * [Designed Screenshots](https://github.com/CS2103AUG2016-F10-C3/main/blob/master/docs/images/Ui.jpg) + * [Designed icon](https://github.com/CS2103AUG2016-F10-C3/main/tree/master/src/main/resources/tary.png) ----- -#### [Leow Yijin](http://github.com/yijinl) -
-Role: Developer
-Responsibilities: Data - ------ - -#### [Martin Choo](http://github.com/m133225) -
-Role: Developer
-Responsibilities: Dev Ops - ------ - -#### [Thien Nguyen](https://github.com/ndt93) - Role: Developer
- Responsibilities: Threading +#### [Voon Soo Yin](http://github.com/tessav) +
- ----- +* Components in charge of: [Logic](https://github.com/se-edu/addressbook-level4/blob/master/docs/DeveloperGuide.md#logic-component) +* Aspects/tools in charge of: Documentation, Travis +* Features implemented: + * [Add task with flexibility in command format]() + * [Add floating task and event task]() + * [Find task by each field type]() + * [Mark task as done]() + * [Separate listing of tasks that are done/not done]() +* Code written: [[functional code](A0130677A.md)][[test code](A0130677A.md)][[docs](A0130677A.md)] +* Other major contributions: + * Command format validation & regex + * Set up Travis + * Complete user guide + +------ -#### [You Liang](http://github.com/yl-coder) -
- Role: Developer
- Responsibilities: UI +#### [Nyan Lin Cho](http://github.com/NachosNLC) +
- ----- +* Components in charge of: [Model](https://github.com/se-edu/addressbook-level4/blob/master/docs/DeveloperGuide.md#model-component) +* Aspects/tools in charge of: Model +* Features implemented: + * [Extended Help Command to view individual command help]() +* Code written: [[functional code](A0139158X.md)][[test code](A0139158X.md)][[docs](A0139158X.md)] -# Contributors +------ -We welcome contributions. See [Contact Us](ContactUs.md) page for more info. +# Acknowledgements -* [Akshay Narayan](https://github.com/se-edu/addressbook-level4/pulls?q=is%3Apr+author%3Aokkhoy) -* [Sam Yong](https://github.com/se-edu/addressbook-level4/pulls?q=is%3Apr+author%3Amauris) \ No newline at end of file +#### [Chan Jun Wei](http://github.com/chanjunweimy) +
+ Role: Module Tutor and Project Supervisor
+ + ----- + +Code modified from : https://github.com/nus-cs2103-AY1617S1/addressbook-level4 diff --git a/docs/ContactUs.md b/docs/ContactUs.md index 866d0de3fddc..baf2113e0f05 100644 --- a/docs/ContactUs.md +++ b/docs/ContactUs.md @@ -1,8 +1,8 @@ # Contact Us -* **Bug reports, Suggestions** : Post in our [issue tracker](https://github.com/se-edu/addressbook-level4/issues) +* **Bug reports, Suggestions** : Post in our [issue tracker](https://github.com/CS2103AUG2016-F10-C3/main/issues) if you noticed bugs or have suggestions on how to improve. * **Contributing** : We welcome pull requests. Follow the process described [here](https://github.com/oss-generic/process) -* **Email us** : You can also reach us at `damith [at] comp.nus.edu.sg` \ No newline at end of file +* **Email us** : You can also reach us at `a0130677@u.nus.edu` diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index bc710ed45eb9..78b40a0de412 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -45,8 +45,9 @@ ## Design ### Architecture - -
+ +
+ The **_Architecture Diagram_** given above explains the high-level design of the App. Given below is a quick overview of each component. @@ -72,19 +73,24 @@ Each of the four components For example, the `Logic` component (see the class diagram given below) defines it's API in the `Logic.java` interface and exposes its functionality using the `LogicManager.java` class.
-
+ +
+ The _Sequence Diagram_ below shows how the components interact for the scenario where the user issues the command `delete 3`. + + + - - ->Note how the `Model` simply raises a `AddressBookChangedEvent` when the Address Book data are changed, +>Note how the `Model` simply raises a `AddressBookChangedEvent` when the GTD data are changed, instead of asking the `Storage` to save the updates to the hard disk. The diagram below shows how the `EventsCenter` reacts to that event, which eventually results in the updates being saved to the hard disk and the status bar of the UI being updated to reflect the 'Last Updated' time.
- + + + > Note how the event is propagated through the `EventsCenter` to the `Storage` and `UI` without `Model` having to be coupled to either of them. This is an example of how this Event Driven approach helps us reduce direct @@ -93,12 +99,13 @@ being saved to the hard disk and the status bar of the UI being updated to refle The sections below give more details of each component. ### UI component - -
+ +
+ **API** : [`Ui.java`](../src/main/java/seedu/address/ui/Ui.java) -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `TaskListPanel`, `StatusBarFooter`, `BrowserPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class and they can be loaded using the `UiPartLoader`. @@ -113,42 +120,43 @@ The `UI` component, * Responds to events raised from various parts of the App and updates the UI accordingly. ### Logic component - -
- + +
+ **API** : [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java) 1. `Logic` uses the `Parser` class to parse the user command. 2. This results in a `Command` object which is executed by the `LogicManager`. -3. The command execution can affect the `Model` (e.g. adding a person) and/or raise events. +3. The command execution can affect the `Model` (e.g. adding a task) and/or raise events. 4. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. Given below is the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` API call.
-
- + +
+ ### Model component - -
- + +
+ **API** : [`Model.java`](../src/main/java/seedu/address/model/Model.java) The `Model`, * stores a `UserPref` object that represents the user's preferences. -* stores the Address Book data. -* exposes a `UnmodifiableObservableList` that can be 'observed' e.g. the UI can be bound to this list +* stores the GTD data. +* exposes a `UnmodifiableObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. * does not depend on any of the other three components. ### Storage component - -
- + +
+ **API** : [`Storage.java`](../src/main/java/seedu/address/storage/Storage.java) The `Storage` component, * can save `UserPref` objects in json format and read it back. -* can save the Address Book data in xml format and read it back. +* can save the GTD data in xml format and read it back. ### Common classes @@ -241,41 +249,48 @@ Here are the steps to create a new release. ### Managing Dependencies -A project often depends on third-party libraries. For example, Address Book depends on the +A project often depends on third-party libraries. For example, Tarydepends on the [Jackson library](http://wiki.fasterxml.com/JacksonHome) for XML parsing. Managing these _dependencies_ can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives.
a. Include those libraries in the repo (this bloats the repo size)
b. Require developers to download those libraries manually (this creates extra work for developers)
+ + ## Appendix A : User Stories Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` - Priority | As a ... | I want to ... | So that I can... -------- | :-------- | :--------- | :----------- -`* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App -`* * *` | user | add a new person | -`* * *` | user | delete a person | remove entries that I no longer need -`* * *` | user | find a person by name | locate details of persons without having to go through the entire list -`* *` | user | hide [private contact details](#private-contact-detail) by default | minimize chance of someone else seeing them by accident -`*` | user with many persons in the address book | sort persons by name | locate a person easily - -{More to be added} +`* * *` | new user | see usage instructions | refer to instructions when I forget how to use the application +`* * *` | user | add a task with a deadline | be reminded of tasks that I have to complete soon and prioritise them +`* * ` | user | add a task with a priority rank | view a prioritised list of tasks and know which task to start with +`* * ` | user | add a task with a location | immediately know the location and context without having to refer to other sources +`* * *` | user | add a task with tag(s) | search or filter tasks by these tags +`* * ` | user | select a task to access widgets like Google Calendar and Google Maps | immediately connect with these frequently used applications, without having to take more steps such as opening a browser and visiting the link, and typing in the search bar +`* * *` | user | delete a task | remove clutter from the task list +`* * *` | user | find a task by title | find tasks easily +`* * *` | user | find a task by tags | categorise and find tasks easily +`* * *` | user | edit information about a task | update the task (such as adding a deadline or location) when more information is available or when changes arise +`* * *` | user | view all tasks entered | have a quick summary of what tasks I have +`* * *` | user | clear all tasks | reset the task list + + ## Appendix B : Use Cases -(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise) +(For all use cases below, the **System** is the `GTD` and the **Actor** is the `user`, unless specified otherwise) -#### Use case: Delete person +#### Use case: Delete task **MSS** 1. User requests to list persons -2. AddressBook shows a list of persons +2. GTD shows a list of persons 3. User requests to delete a specific person in the list -4. AddressBook deletes the person
+4. GTD deletes the person
Use case ends. **Extensions** @@ -286,7 +301,7 @@ Use case ends. 3a. The given index is invalid -> 3a1. AddressBook shows an error message
+> 3a1. GTD shows an error message
Use case resumes at step 2 {More to be added} @@ -294,7 +309,7 @@ Use case ends. ## Appendix C : Non Functional Requirements 1. Should work on any [mainstream OS](#mainstream-os) as long as it has Java `1.8.0_60` or higher installed. -2. Should be able to hold up to 1000 persons. +2. Should be able to hold up to 10,000 tasks. 3. Should come with automated unit tests and open source code. 4. Should favor DOS style commands over Unix-style commands. @@ -306,11 +321,28 @@ Use case ends. > Windows, Linux, Unix, OS-X -##### Private contact detail - -> A contact detail that is not meant to be shared with others + ## Appendix E : Product Survey -{TODO: Add a summary of competing products} - +Reminders for Mac: Simple, clean white interface that is close to a text editor. Mouse use for interaction only required for tags, adding and deleting. +Features: +a) tags can be added to items on the list like date due and priority +b) schedule tab can arrange the reminders by due date +c) iCloud sync allows use on laptop and phone +d) periodic tasks can be set such that a reminder alert is displayed every time it is due. + +Drawbacks: +a) Need to refer to calendar to set due dates. + +Asana: Collaborative GTD, a team can set up project tasks and subgroups that divide people into smaller groups based on tasks (Marketing, Engineering, etc). +a) Can setup individual tasks on personal dashboard, so it also works well for individual use. +b) Can hold conversations with team members. +c) Can set up team tasks. +d) Can divide members into smaller groups for better organisation. + +Taskwarrior: feature-rich software that allows the user to manage his todo list from the command line. +Uses a natural and expressive syntax +Allows user to perform CRUD functions and prioritising of tasks in a fast manner +Support for creating deadlines, searching of tasks +However, it does not support Jim’s need for “blocking� and “unblocking� timeslots diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 0cf4b84f7470..879aba4ae4a1 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -8,127 +8,178 @@ ## Quick Start 0. Ensure you have Java version `1.8.0_60` or later installed in your Computer.
- > Having any Java 8 version is not enough.
- This app will not work with earlier versions of Java 8. - -1. Download the latest `addressbook.jar` from the [releases](../../../releases) tab. +Having any Java 8 version is not enough.
+This app will not work with earlier versions of Java 8. +1. Download the latest `taryapp.jar` from the [releases](../../../releases) tab. 2. Copy the file to the folder you want to use as the home folder for your Address Book. -3. Double-click the file to start the app. The GUI should appear in a few seconds. - > +3. Double-click the file to start the app. The GUI should appear in a few seconds.
+ + 4. Type the command in the command box and press Enter to execute it.
e.g. typing **`help`** and pressing Enter will open the help window. 5. Some example commands you can try: - * **`list`** : lists all contacts - * **`add`**` John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01` : - adds a contact named `John Doe` to the Address Book. - * **`delete`**` 3` : deletes the 3rd contact shown in the current list + * **`list`** : lists all tasks to be done + * **`add`**` add Visit Dentist d/18-11-2016 a/Mount Elizabeth` : + adds a task named `Visit Dentist` to the Task List. + * **`delete`**` 3` : deletes the 3rd task shown in the current list * **`exit`** : exits the app 6. Refer to the [Features](#features) section below for details of each command.
- ## Features - -> **Command Format** -> * Words in `UPPER_CASE` are the parameters. -> * Items in `SQUARE_BRACKETS` are optional. -> * Items with `...` after them can have multiple instances. -> * The order of parameters is fixed. - -#### Viewing help : `help` +
+### Command Format +* Words in `UPPER_CASE` are the parameters. +* Items in `SQUARE_BRACKETS` are optional. +* Items with `...` after them can have multiple instances. +* The order of parameters is fixed. +


+ +### Viewing help : `help` Format: `help` - -> Help is also shown if you enter an incorrect command e.g. `abcd` - -#### Adding a person: `add` -Adds a person to the address book
-Format: `add NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` - -> Persons can have any number of tags (including 0) +* Help is also shown if you enter an incorrect command e.g. `abcd` +


+ +### Adding a person: `add` +**Format:** `add NAME [a/LOCATION s/START_DATE d/DEADLINE_OR_END_DATE p/PRIORITY t/TAGS]`
+* Adds a task to the task list in a flexible format (in any order). +* All parameters except name are optional. +* This command supports 3 types of tasks: floating tasks, event tasks and deadline tasks. +* Persons can have any number of tags (including 0) +
+Examples: +* Floating task: `add Visit Dentist` +* Event task: `add hackathon a/NUS s/tomorrow d/sunday p/3 t/preparation` +* Deadline task: `add submit tutorial d/monday p/5` + +**Field Type Constraints** +* Task duedate or startdate is formatted like the following: Wed Nov 02 15:39:55 UTC 2016 +* Accepted formal dates: 1978-01-28, 1984/04/02, 1/02/1980, 2/28/79 +* Relaxed dates: The 31st of April in the year 2008, Fri, 21 Nov 1997, Jan 21, '97, Sun, Nov 21, jan 1st, february twenty-eighth +* Relative dates: next thursday, last wednesday, today, tomorrow, yesterday, next week, next month, next year, 3 days from * now, three weeks ago +* Prefixes: day after, the day before, the monday after, the monday before, 2 fridays before, 4 tuesdays after +* Time: 0600h, 06:00 hours, 6pm, 5:30 a.m., 5, 12:59, 23:59, 8p, noon, afternoon, midnight +* Relative times: 10 seconds ago, in 5 minutes, 4 minutes from now. +


+ +### Mark task as done : `done` +Format: `done INDEX` +Marks a task as done by the index displayed on the task panel.
+* tasks marked as done can be shown when using command 'list done' +* once marked as done, cannot be undone unless using `undone` command immediately +


+ +### Edit task by attributes: `edit` +Format: `edit INDEX [NEW_NAME] FIELD_TYPE/NEW_FIELD_DETAILS` +Edits a task as done by the index displayed on the task panel.
+* to change the name only, use `edit NEW_NAME` without specifying field type +* able to accept multiple field types e.g. `edit 2 taskA a/NUS d/friday` +


+ +### Undo previous command: `undo` +Format: `undo` +Undo the last command.
+* multiple undos supported. +


+ +### Listing all tasks : `list` +Format: `list [done]` +Shows a list of all tasks done or not done in the task list.
+* `list` shows all tasks not done +* `list done` shows all tasks done +


+ +### Finding all tasks containing any keyword in their name or attributes: `find` +Format: `find [FIELD_TYPE] KEYWORD` +Finds tasks whose descriptions contain any of the given keyword.
+* The search is case sensitive. e.g `hmk` will not match `HMK` +* The order of the keywords does not matter. e.g. `Do Homework` will match `Homework Do` +* If field type is specified, only the field type will be matched with the keyword +* If field type is not specified, name will be search for a match first, before searching all the other fields for the keyword. +* Only full words will be matched e.g. `Hmk` will not match `Hmks` +* Tasks matching at least one keyword will be returned (i.e. `OR` search). + e.g. `Hmk` will match `Do Hmk` Examples: -* `add John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01` -* `add Betsy Crowe p/1234567 e/betsycrowe@gmail.com a/Newgate Prison t/criminal t/friend` - -#### Listing all persons : `list` -Shows a list of all persons in the address book.
-Format: `list` +* `find p/3` : Returns any task that has priority 3 +* `find a/NUS` : Returns any task that occurs in NUS +* `find homework`: Returns task with homework in the name, if not found, returns tasks with homework in other fields such as tags +


-#### Finding all persons containing any keyword in their name: `find` -Finds persons whose names contain any of the given keywords.
-Format: `find KEYWORD [MORE_KEYWORDS]` - -> * The search is case sensitive. e.g `hans` will not match `Hans` -> * The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -> * Only the name is searched. -> * Only full words will be matched e.g. `Han` will not match `Hans` -> * Persons matching at least one keyword will be returned (i.e. `OR` search). - e.g. `Hans` will match `Hans Bo` - -Examples: -* `find John`
- Returns `John Doe` but not `john` -* `find Betsy Tim John`
- Returns Any person having names `Betsy`, `Tim`, or `John` - -#### Deleting a person : `delete` -Deletes the specified person from the address book. Irreversible.
+### Deleting a task : `delete` +Deletes the specified task from the address book. Irreversible.
Format: `delete INDEX` -> Deletes the person at the specified `INDEX`. - The index refers to the index number shown in the most recent listing.
- The index **must be a positive integer** 1, 2, 3, ... +Deletes the task at the specified `INDEX`. +The index refers to the index number shown in the most recent listing.
+The index **must be a positive integer** 1, 2, 3, ... Examples: * `list`
`delete 2`
- Deletes the 2nd person in the address book. -* `find Betsy`
+ Deletes the 2nd task in the task list. +* `find CS2101`
`delete 1`
- Deletes the 1st person in the results of the `find` command. + Deletes the 1st task in the results of the `find` command. +


-#### Select a person : `select` +### Select a person : `select` Selects the person identified by the index number used in the last person listing.
Format: `select INDEX` -> Selects the person and loads the Google search page the person at the specified `INDEX`. - The index refers to the index number shown in the most recent listing.
- The index **must be a positive integer** 1, 2, 3, ... +Selects the person and loads the Google Maps for location of the task at the specified `INDEX`. +The index refers to the index number shown in the most recent listing.
+The index **must be a positive integer** 1, 2, 3, ... Examples: * `list`
`select 2`
- Selects the 2nd person in the address book. -* `find Betsy`
+ Selects the 2nd task in the task list. +* `find a/NUS`
`select 1`
- Selects the 1st person in the results of the `find` command. - -#### Clearing all entries : `clear` -Clears all entries from the address book.
-Format: `clear` - -#### Exiting the program : `exit` + Selects the 1st task in the results of the `find` command. +


+ +### Clearing all entries : `clear` +Clears all entries from the task list.
+Format: `clear` +


+ +### Change file path of storage : `setPath` +Change the path of the task list to be stored to the specified file path.
+Format: `setPath NEW_PATH` +Example: +* `setPath data/newfilepath.xml` +


+ +### Exiting the program : `exit` Exits the program.
Format: `exit` +


-#### Saving the data -Address book data are saved in the hard disk automatically after any command that changes the data.
+### Saving the data +Task List data are saved in the hard disk automatically after any command that changes the data.
There is no need to save manually. +


## FAQ **Q**: How do I transfer my data to another Computer?
**A**: Install the app in the other computer and overwrite the empty data file it creates with - the file that contains the data of your previous Address Book folder. - + the file that contains the data of your previous Tasks folder. +

## Command Summary Command | Format -------- | :-------- -Add | `add NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]...` +Add | `add NAME [s/startdate d/duedate a/address p/priorityrank(1- highest,5-lowest) t/TAG]...` +Edit | `edit INDEX [NEW_NAME] FIELD_TYPE/NEW_FIELD_DETAILS` where FIELD_TYPE is either `d/` `a/` `s/` `p/` +Done | `done INDEX` Clear | `clear` Delete | `delete INDEX` -Find | `find KEYWORD [MORE_KEYWORDS]` -List | `list` +Find | `find [FIELD_TYPE] KEYWORD` FIELD_TYPE options: `t/` `a/` `s/` `d/` `p/` +List | `list [done]` Help | `help` Select | `select INDEX` +SetPath | `setPath NEW_FILE_PATH` NEW_FILE_PATH: e.g. `data/newfile.xml` +Exit | `exit` diff --git a/docs/UsingGradle.md b/docs/UsingGradle.md index 578c5f8634c2..2bf08c342563 100644 --- a/docs/UsingGradle.md +++ b/docs/UsingGradle.md @@ -35,7 +35,7 @@ Gradle commands look like this: ## Creating the JAR file * **`shadowJar`**
- Creates the `addressbook.jar` file in the `build/jar` folder, _if the current file is outdated_.
+ Creates the `tary.jar` file in the `build/jar` folder, _if the current file is outdated_.
e.g. `./gradlew shadowJar` > To force Gradle to create the JAR file even if the current one is up-to-date, you can '`clean`' first.
diff --git a/docs/diagrams/Diagrams.pptx b/docs/diagrams/Diagrams.pptx index 3c28abe9c1d3..422ba6686c76 100644 Binary files a/docs/diagrams/Diagrams.pptx and b/docs/diagrams/Diagrams.pptx differ diff --git a/docs/images/ChanJunWei.jpg b/docs/images/ChanJunWei.jpg new file mode 100644 index 000000000000..9006d5e190e3 Binary files /dev/null and b/docs/images/ChanJunWei.jpg differ diff --git a/docs/images/DeleteTaskSdForLogic.png b/docs/images/DeleteTaskSdForLogic.png new file mode 100644 index 000000000000..6a435503ce5a Binary files /dev/null and b/docs/images/DeleteTaskSdForLogic.png differ diff --git a/docs/images/LeowYijin.jpg b/docs/images/LeowYijin.jpg deleted file mode 100644 index adbf62ad9406..000000000000 Binary files a/docs/images/LeowYijin.jpg and /dev/null differ diff --git a/docs/images/MockupUi.jpg b/docs/images/MockupUi.jpg new file mode 100644 index 000000000000..5c630f6375c9 Binary files /dev/null and b/docs/images/MockupUi.jpg differ diff --git a/docs/images/Nachos.jpg b/docs/images/Nachos.jpg new file mode 100644 index 000000000000..30a3404d8d71 Binary files /dev/null and b/docs/images/Nachos.jpg differ diff --git a/docs/images/RaviShwetha.jpg b/docs/images/RaviShwetha.jpg new file mode 100644 index 000000000000..75fb9d59119e Binary files /dev/null and b/docs/images/RaviShwetha.jpg differ diff --git a/docs/images/SDforDeleteTask.png b/docs/images/SDforDeleteTask.png new file mode 100644 index 000000000000..191d1536b262 Binary files /dev/null and b/docs/images/SDforDeleteTask.png differ diff --git a/docs/images/SDforDeleteTaskEventHandling.png b/docs/images/SDforDeleteTaskEventHandling.png new file mode 100644 index 000000000000..183f5270e426 Binary files /dev/null and b/docs/images/SDforDeleteTaskEventHandling.png differ diff --git a/docs/images/ShaoYun.jpg b/docs/images/ShaoYun.jpg new file mode 100644 index 000000000000..982c35cbfd95 Binary files /dev/null and b/docs/images/ShaoYun.jpg differ diff --git a/docs/images/SooYin.jpg b/docs/images/SooYin.jpg new file mode 100644 index 000000000000..8d4ce5f10a99 Binary files /dev/null and b/docs/images/SooYin.jpg differ diff --git a/docs/images/TaryArchitecture.png b/docs/images/TaryArchitecture.png new file mode 100644 index 000000000000..2a06e7d443fc Binary files /dev/null and b/docs/images/TaryArchitecture.png differ diff --git a/docs/images/TaskLogicClassDiagram.png b/docs/images/TaskLogicClassDiagram.png new file mode 100644 index 000000000000..fc1bed6e7c7c Binary files /dev/null and b/docs/images/TaskLogicClassDiagram.png differ diff --git a/docs/images/TaskModelClassDiagram.png b/docs/images/TaskModelClassDiagram.png new file mode 100644 index 000000000000..7c21c850dbf2 Binary files /dev/null and b/docs/images/TaskModelClassDiagram.png differ diff --git a/docs/images/TaskStorageClassDiagram.png b/docs/images/TaskStorageClassDiagram.png new file mode 100644 index 000000000000..7a63c30592bd Binary files /dev/null and b/docs/images/TaskStorageClassDiagram.png differ diff --git a/docs/images/TaskUiClassDiagram.png b/docs/images/TaskUiClassDiagram.png new file mode 100644 index 000000000000..b4ae4579f2f2 Binary files /dev/null and b/docs/images/TaskUiClassDiagram.png differ diff --git a/docs/images/Ui.jpg b/docs/images/Ui.jpg new file mode 100644 index 000000000000..752445ac6355 Binary files /dev/null and b/docs/images/Ui.jpg differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png deleted file mode 100644 index 7121a50a442a..000000000000 Binary files a/docs/images/Ui.png and /dev/null differ diff --git a/docs/images/Architecture.png b/docs/images/oldPics/Architecture.png similarity index 100% rename from docs/images/Architecture.png rename to docs/images/oldPics/Architecture.png diff --git a/docs/images/DamithRajapakse.jpg b/docs/images/oldPics/DamithRajapakse.jpg similarity index 100% rename from docs/images/DamithRajapakse.jpg rename to docs/images/oldPics/DamithRajapakse.jpg diff --git a/docs/images/DeletePersonSdForLogic.png b/docs/images/oldPics/DeletePersonSdForLogic.png similarity index 100% rename from docs/images/DeletePersonSdForLogic.png rename to docs/images/oldPics/DeletePersonSdForLogic.png diff --git a/docs/images/JoshuaLee.jpg b/docs/images/oldPics/JoshuaLee.jpg similarity index 100% rename from docs/images/JoshuaLee.jpg rename to docs/images/oldPics/JoshuaLee.jpg diff --git a/docs/images/LogicClassDiagram.png b/docs/images/oldPics/LogicClassDiagram.png similarity index 100% rename from docs/images/LogicClassDiagram.png rename to docs/images/oldPics/LogicClassDiagram.png diff --git a/docs/images/MartinChoo.jpg b/docs/images/oldPics/MartinChoo.jpg similarity index 100% rename from docs/images/MartinChoo.jpg rename to docs/images/oldPics/MartinChoo.jpg diff --git a/docs/images/ModelClassDiagram.png b/docs/images/oldPics/ModelClassDiagram.png similarity index 100% rename from docs/images/ModelClassDiagram.png rename to docs/images/oldPics/ModelClassDiagram.png diff --git a/docs/images/SDforDeletePerson.png b/docs/images/oldPics/SDforDeletePerson.png similarity index 100% rename from docs/images/SDforDeletePerson.png rename to docs/images/oldPics/SDforDeletePerson.png diff --git a/docs/images/SDforDeletePersonEventHandling.png b/docs/images/oldPics/SDforDeletePersonEventHandling.png similarity index 100% rename from docs/images/SDforDeletePersonEventHandling.png rename to docs/images/oldPics/SDforDeletePersonEventHandling.png diff --git a/docs/images/StorageClassDiagram.png b/docs/images/oldPics/StorageClassDiagram.png similarity index 100% rename from docs/images/StorageClassDiagram.png rename to docs/images/oldPics/StorageClassDiagram.png diff --git a/docs/images/UiClassDiagram.png b/docs/images/oldPics/UiClassDiagram.png similarity index 100% rename from docs/images/UiClassDiagram.png rename to docs/images/oldPics/UiClassDiagram.png diff --git a/docs/images/YouLiang.jpg b/docs/images/oldPics/YouLiang.jpg similarity index 100% rename from docs/images/YouLiang.jpg rename to docs/images/oldPics/YouLiang.jpg diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000000..01d3db6c4830 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,13 @@ + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam interdum eget justo ut ultrices. Mauris condimentum sollicitudin diam, sed placerat leo consectetur et. Proin porttitor commodo turpis, vitae vehicula purus. In suscipit lacinia augue ac convallis. Donec sed feugiat turpis. Donec iaculis vel ex non viverra. Cras lobortis maximus tellus, ac dictum tellus aliquam quis. Vivamus sed libero suscipit, maximus nisi id, ultricies ante. Aenean a libero lectus. Proin iaculis tincidunt velit nec dictum. Fusce vitae nisi nunc. Maecenas in ultricies metus, nec sollicitudin dolor. In vulputate suscipit quam sed tristique. Aenean at hendrerit massa, fringilla volutpat ex. + +Vestibulum nec lobortis quam, a elementum magna. Cras tristique nec nibh in tincidunt. Nulla luctus rutrum neque, non hendrerit mi pulvinar sit amet. Etiam lectus elit, mattis ut interdum ut, pulvinar et sem. Nam efficitur venenatis magna sed rhoncus. Mauris est ex, ullamcorper non cursus vitae, tincidunt ac mi. Morbi blandit sollicitudin metus sit amet feugiat. Aliquam erat volutpat. Nam id imperdiet quam, quis convallis dolor. + +Aliquam placerat quam eu tincidunt luctus. Praesent vestibulum nunc semper orci consequat sodales. Pellentesque cursus neque mi, at tempor nulla eleifend eget. Nam finibus maximus leo sit amet sagittis. Aliquam scelerisque facilisis molestie. Pellentesque ullamcorper tincidunt ex in ullamcorper. Donec eget venenatis ex. Mauris sagittis congue ligula, sit amet faucibus dolor elementum eu. Sed et turpis sit amet massa cursus ornare a vitae nisl. Curabitur et erat in neque rhoncus pretium viverra nec augue. Nulla vestibulum est at velit pharetra, sed suscipit felis molestie. Quisque venenatis sagittis mi maximus venenatis. Maecenas turpis odio, luctus vitae mollis vel, rhoncus ac ante. + +Nullam posuere pulvinar dolor vitae malesuada. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tempor facilisis sem, sed vehicula metus efficitur eu. Nullam tristique ac elit in gravida. Phasellus aliquet ut nunc ut scelerisque. Morbi nec arcu diam. Nunc hendrerit lacinia pulvinar. Integer accumsan auctor dolor, at lacinia leo consectetur at. Nam tristique dolor augue, eu pharetra neque dignissim non. Pellentesque bibendum tincidunt leo, feugiat pretium felis facilisis ac. Nulla id gravida velit. Cras ullamcorper neque sit amet magna facilisis tempus. Nulla quis erat eget ante semper consectetur vitae in metus. Etiam quis urna lectus. + +Curabitur tempor ullamcorper turpis, vitae scelerisque mauris tristique sit amet. Praesent scelerisque tincidunt orci a ullamcorper. Aliquam convallis eros vitae enim auctor vulputate. Sed dignissim interdum accumsan. Aenean at dui nec mi tempor sagittis sit amet semper nunc. Integer fringilla tortor leo, in consequat nulla consectetur id. Phasellus rutrum sapien velit, sit amet scelerisque augue iaculis sollicitudin. Etiam a finibus metus. + + \ No newline at end of file diff --git a/libs/A0146130W.md b/libs/A0146130W.md new file mode 100644 index 000000000000..f7882e9c3111 --- /dev/null +++ b/libs/A0146130W.md @@ -0,0 +1,535 @@ +# A0146130W +###### /src/main/java/seedu/gtd/commons/exceptions/DataConversionException.java +``` java + public DataConversionException(String cause) { + super(cause); + } +} +``` +###### /src/main/java/seedu/gtd/logic/commands/EditCommand.java +``` java + /** + * Adds a task to the address book. + */ + public class EditCommand extends Command { + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ":\n" + + "Edits the task identified by the index number used in the last task listing.\n\t" + + "Parameters: [INDEX] (must be a positive integer) prefix/[NEW DETAIL]\n\t" + + "Example: " + COMMAND_WORD + + " 1 p/9"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Task updated: %1$s"; + + private int targetIndex; + private String detailType; + private String newDetail; + + public EditCommand(int targetIndex, String detailType, String newDetail) { + this.targetIndex = targetIndex; + this.detailType = detailType; + this.newDetail = newDetail; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask toEdit = lastShownList.get(targetIndex); + Task taskToUpdate = new Task(toEdit); + + try { + taskToUpdate = updateTask(taskToUpdate, detailType, newDetail); + } catch (IllegalValueException ive) { + return new CommandResult(ive.getMessage()); + } + + assert model != null; + try { + model.editTask(targetIndex, taskToUpdate); + } catch (TaskNotFoundException e) { + assert false : "The target task cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToUpdate)); + + } + + private Task updateTask(Task taskToUpdate, String detailType, String newDetail) throws IllegalValueException { + taskToUpdate.edit(detailType, newDetail); + return taskToUpdate; + } + + } +``` +###### /src/main/java/seedu/gtd/logic/commands/FindCommand.java +``` java + private final String keywords; + private Set keywordSet; + private final String cmd; + + public FindCommand(String keywords, Set keywordSet, String cmd) { + this.keywords = keywords; + this.keywordSet = keywordSet; + this.cmd = cmd; + } + + private String getMessageForTaskListShownSummaryIfExactPhraseNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } + + private String getMessageForTaskListShownSummaryIfExactFieldNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found in the specified field type. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } + + @Override + public CommandResult execute() { + System.out.println("command: " + cmd); + + // search by parameter if specified + if (cmd != "nil") { + model.updateFilteredTaskList(keywords, cmd); + } else { + // search by exact name + model.updateFilteredTaskList(keywords, keywordSet); + } + if (!model.getFilteredTaskList().isEmpty()) { + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } + + // search by keywords + model.updateFilteredTaskList(keywords, "nil"); + + if (!model.getFilteredTaskList().isEmpty()) { + if (cmd == "nil") { + return new CommandResult(getMessageForTaskListShownSummaryIfExactPhraseNotFound(model.getFilteredTaskList().size())); + } else { + return new CommandResult(getMessageForTaskListShownSummaryIfExactFieldNotFound(model.getFilteredTaskList().size())); + } + } + + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } +} +``` +###### /src/main/java/seedu/gtd/logic/commands/UndoCommand.java +``` java + +package seedu.gtd.logic.commands; + +/** + * Deletes a task identified using it's last displayed index from the address book. + */ +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Un-does the most recent modification of the task list."; + public static final String MESSAGE_SUCCESS = "Undo change"; + + public UndoCommand() {} + + @Override + public CommandResult execute() { + model.undoAddressBookChange(); + return new CommandResult(MESSAGE_SUCCESS); + } + +} +``` +###### /src/main/java/seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java +``` java + +/** + * Uses natty API: http://natty.joestelmach.com to parse natural language into dates or string + */ +public class DateNaturalLanguageProcessor implements NaturalLanguageProcessor { + + private static final com.joestelmach.natty.Parser parser = new com.joestelmach.natty.Parser(); + private static final String DATE_FORMAT = "dd/MM/yyyy HH:mm"; + + @Override + public String formatString(String naturalLanguageDate) { + List dateGroups = parser.parse(naturalLanguageDate); + Date parsedDate; + try { + parsedDate = refineDateGroupList(dateGroups); + } catch (NaturalLanguageException e) { + return ""; + } + return formatDateToString(parsedDate); + } + + /** + * Chooses the first date from a list of dates that Natty has parsed from the natural language string + * @throws NaturalLanguageException + * */ + private Date refineDateGroupList(List groups) throws NaturalLanguageException { + if(groups.size() == 0) throw new NaturalLanguageException(); + return groups.get(0).getDates().get(0); + } + + private String formatDateToString(Date date) { + Format formatter = new SimpleDateFormat(DATE_FORMAT); + return formatter.format(date); + } +} +``` +###### /src/main/java/seedu/gtd/logic/parser/NaturalLanguageProcessor.java +``` java + +package seedu.gtd.logic.parser; + +import seedu.gtd.commons.exceptions.DataConversionException; + +public interface NaturalLanguageProcessor { + + /** Takes in a string written in natural language and formats it.*/ + String formatString(String s); + + public static class NaturalLanguageException extends DataConversionException { + protected NaturalLanguageException() { + super("Natural Language Processor was unable to convert input"); + } + } +} +``` +###### /src/main/java/seedu/gtd/logic/parser/Parser.java +``` java + + private String parseDueDate(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.formatString(dueDateRaw); + } + + // remove time on date parsed to improve search results + private String removeTimeOnDate(String dueDateRaw) { + String[] dateTime = dueDateRaw.split(" "); + return dateTime[0]; + } + +``` +###### /src/main/java/seedu/gtd/logic/parser/Parser.java +``` java + /** + * Parses arguments in the context of the edit task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareEdit(String args) { + + final Matcher matcher = EDIT_DATA_ARGS_FORMAT.matcher(args.trim()); + // Validate arg string format + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + + Optional index = Optional.of(Integer.parseInt(matcher.group("targetIndex"))); + String newDetail = matcher.group("newDetail"); + + String detailType = extractDetailType(newDetail); + newDetail = prepareNewDetail(detailType, newDetail); + + return new EditCommand( + (index.get() - 1), + detailType, + newDetail + ); + } + + private String extractDetailType(String detailType) { + switch(detailType.substring(0, 2)) { + case "d/": return "dueDate"; + case "a/": return "address"; + case "p/": return "priority"; + default: return "name"; + } + } + + private String prepareNewDetail(String detailType, String newDetail) { + + if(detailType == "name") { + return newDetail; + } + + newDetail = newDetail.substring(2); + if(detailType == "dueDate") { + newDetail = parseDueDate(newDetail); + } + return newDetail; + } + +``` +###### /src/main/java/seedu/gtd/model/AddressBook.java +``` java + /** + * Edits a task in the address book. + * Also checks the updated task's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the task to point to those in {@link #tags}. + * + * @throws UniqueTaskList.TaskNotFoundException if the task was not found. + */ + public void editTask(int index, Task t) throws UniqueTaskList.TaskNotFoundException { + syncTagsWithMasterList(t); + tasks.edit(index, t); + } + +``` +###### /src/main/java/seedu/gtd/model/ModelManager.java +``` java + @Override + public synchronized void editTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + System.out.println("editing task.."); + addressBook.editTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + + @Override + public void clearTaskList() { + savePreviousAddressBook(); + resetData(AddressBook.getEmptyAddressBook()); + } + +``` +###### /src/main/java/seedu/gtd/model/task/UniqueTaskList.java +``` java + /** + * Edits an equivalent task from the list. + * + * @throws TaskNotFoundException if no such task could be found in the list. + */ + public void edit(int targetIndex, Task toEdit) throws TaskNotFoundException { + assert toEdit != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + internalList.set(targetIndex, toEdit); + } + + public void done(int targetIndex, Task taskdone) throws TaskNotFoundException { + System.out.println("in uniquetasklist"); + System.out.println(taskdone.getName() + " " + taskdone.getisDone()); + System.out.println("index at final:" + targetIndex); + assert taskdone != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + System.out.println("marked done in model"); + internalList.set(targetIndex, taskdone); + } + + private boolean invalidIndex(int i) { + if(i < 0 || i >= internalList.size()) return true; + return false; + } + +``` +###### /src/test/java/guitests/EditCommandTest.java +``` java + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.EditCommand.MESSAGE_EDIT_TASK_SUCCESS; + +public class EditCommandTest extends AddressBookGuiTest { + + @Test + public void edit() { + + //edit the priority of the first task + TestTask[] currentList = td.getTypicalTasks(); + int targetIndex = 1; + String change = "p/4"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the dueDate of the last in the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + targetIndex = currentList.length; + change = "d/2"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the name task from the middle of the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + targetIndex = currentList.length/2; + change = "Tutorial 4"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the address task from the middle of the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + change = "a/NTU"; + assertEditSuccess(targetIndex, change, currentList); + + //invalid index + commandBox.runCommand("edit " + currentList.length + 1 + " Invalid"); + assertResultMessage("The task index provided is invalid"); + + } + + /** + * Runs the edit command to edit the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to edit the first task in the list, 1 should be given as the target index. + * @param currentList A copy of the current list of tasks (before editing). + */ + private void assertEditSuccess(int targetIndexOneIndexed, String change, final TestTask[] currentList) { + TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestTask[] expectedRemainder = TestUtil.editTaskInList(currentList, targetIndexOneIndexed, change, taskToEdit); + commandBox.runCommand("edit " + targetIndexOneIndexed + " " + change); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_EDIT_TASK_SUCCESS, expectedRemainder[targetIndexOneIndexed-1])); + } + +} +``` +###### /src/test/java/guitests/UndoCommandTest.java +``` java + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_SUCCESS;; + +public class UndoCommandTest extends AddressBookGuiTest { + + @Test + public void undo() { + + //undo the addition of the first task + TestTask[] currentList = td.getTypicalTasks(); + TestTask[] previousList = currentList; + commandBox.runCommand(td.george.getAddCommand()); + assertUndoSuccess(previousList); + + //undo editing the dueDate of the last task in the list + int targetIndex = currentList.length; + String change = "d/2"; + previousList = currentList; + commandBox.runCommand("edit " + targetIndex + " " + change); + assertUndoSuccess(previousList); + + //undo deleting a task from the middle of the list + targetIndex = currentList.length/2; + previousList = currentList; + commandBox.runCommand("delete " + targetIndex); + assertUndoSuccess(previousList); + + //undo clearing list + previousList = currentList; + commandBox.runCommand("clear"); + assertUndoSuccess(previousList); + + //undo marking the middle task as done + previousList = currentList; + commandBox.runCommand("done " + targetIndex); + assertUndoSuccess(previousList); + } + + /** + * Runs the undo command to undo the last change to the task list + */ + private void assertUndoSuccess(final TestTask[] previousList) { + commandBox.runCommand("undo"); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(previousList)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + +} +``` +###### /src/test/java/seedu/gtd/testutil/TestUtil.java +``` java + + /** + * Edits a task in the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. + * @throws IllegalValueException + */ + public static TestTask[] editTaskInList(final TestTask[] tasks, int index, String change, TestTask taskToEdit) { + List listOfTasks = asList(tasks); + TestTask taskEditted; + try { + taskEditted = TestUtilParser.editTask(taskToEdit, change); + } catch (IllegalValueException e) { + taskEditted = taskToEdit; + e.printStackTrace(); + } + listOfTasks.set(index-1, taskEditted); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + +``` +###### /src/test/java/seedu/gtd/testutil/TestUtilParser.java +``` java + +package seedu.gtd.testutil; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.logic.parser.DateNaturalLanguageProcessor; +import seedu.gtd.logic.parser.NaturalLanguageProcessor; +import seedu.gtd.model.task.Address; +import seedu.gtd.model.task.DueDate; +import seedu.gtd.model.task.Name; +import seedu.gtd.model.task.Priority; + +/** + * A utility class that parses tasks for test cases. + */ +public class TestUtilParser { + + public static TestTask editTask(TestTask task, String change) throws IllegalValueException { + + TestTask newTask = task; + String changeWithoutPrefix = change.substring(2); + String changePrefix = change.substring(0, 2); + System.out.println("From TestUtil Parser: " + changePrefix + " " + changeWithoutPrefix); + + switch(change.substring(0, 2)) { + case "d/": newTask = new TestTask(task.getName(), new DueDate(parseDueDate(changeWithoutPrefix)), task.getAddress(), task.getPriority(), task.getTags()); break; + case "a/": newTask = new TestTask(task.getName(), task.getDueDate(), new Address(changeWithoutPrefix), task.getPriority(), task.getTags()); break; + case "p/": newTask = new TestTask(task.getName(), task.getDueDate(), task.getAddress(), new Priority(changeWithoutPrefix), task.getTags()); break; + default: newTask = new TestTask(new Name(change), task.getDueDate(), task.getAddress(), task.getPriority(), task.getTags()); + } + return newTask; + } + + public static String parseDueDate(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.formatString(dueDateRaw); + } +} +``` diff --git a/libs/A0146130WreusedToTest.md b/libs/A0146130WreusedToTest.md new file mode 100644 index 000000000000..b3041d81ba9b --- /dev/null +++ b/libs/A0146130WreusedToTest.md @@ -0,0 +1,17 @@ +# A0146130WreusedToTest +###### /src/test/java/seedu/gtd/logic/LogicManagerTest.java +``` java + @Test + public void execute_help() throws Exception { + assertCommandBehavior("help", HelpCommand.MESSAGE_USAGE+"/n"+HelpCommand.SHOWING_HELP_MESSAGE); + assertTrue(helpShown); + assertCommandBehavior("help add", AddCommand.MESSAGE_USAGE); + assertCommandBehavior("help select", SelectCommand.MESSAGE_USAGE); + assertCommandBehavior("help delete", DeleteCommand.MESSAGE_USAGE); + assertCommandBehavior("help clear", ClearCommand.MESSAGE_USAGE); + assertCommandBehavior("help find", FindCommand.MESSAGE_USAGE); + assertCommandBehavior("help list", ListCommand.MESSAGE_USAGE); + assertCommandBehavior("help exit", ExitCommand.MESSAGE_USAGE); + } + +``` diff --git a/libs/addressbooklevel4.md b/libs/addressbooklevel4.md new file mode 100644 index 000000000000..75c99362d388 --- /dev/null +++ b/libs/addressbooklevel4.md @@ -0,0 +1,1905 @@ +# addressbooklevel4 +###### /src/main/java/seedu/gtd/logic/commands/FindCommand.java +``` java + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose name, date, address, tags and priority contain any of " + + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" + + "To search by one particular field type, use t/ for tags, a/ for address, d/ for duedate and p/ for priority.\n" + + "Parameters: [FIELDTYPE] KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " cs2103, " + COMMAND_WORD + " d/today"; + +``` +###### /src/main/java/seedu/gtd/logic/parser/Parser.java +``` java + + /** + * Used for initial separation of command word and args. + */ + private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); + + private static final Pattern TASK_INDEX_ARGS_FORMAT = Pattern.compile("(?.+)"); + + private static final Pattern KEYWORDS_ARGS_FORMAT = + Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace + +// private static final Pattern TASK_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes +// Pattern.compile("(?[^/]+)" +// + " d/(?[^/]+)" +// + " a/(?
[^/]+)" +// + " p/(?[^/]+)" +// + "(?(?: t/[^/]+)*)"); // variable number of tags + + private static final Pattern NAME_TASK_DATA_ARGS_FORMAT = + Pattern.compile("(?[^/]+) (t|p|a|d|z)/.*"); + + private static final Pattern PRIORITY_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* p/(?[^/]+) (t|a|d|z)/.*"); + + private static final Pattern ADDRESS_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* a/(?
[^/]+) (t|p|d|z)/.*"); + + private static final Pattern DUEDATE_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* d/(?[^/]+) (t|a|p|z)/.*"); + + private static final Pattern TAGS_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* t/(?[^/]+) (d|a|p|z)/.*"); + + private static final Pattern EDIT_DATA_ARGS_FORMAT = + Pattern.compile("(?\\S+)" + + " (?.*)"); + + public Parser() {} + + /** + * Parses user input into command for execution. + * + * @param userInput full user input string + * @return the command based on the user input + */ + public Command parseCommand(String userInput) { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + final String arguments = matcher.group("arguments"); + switch (commandWord) { + + case AddCommand.COMMAND_WORD: + return prepareAdd(arguments); + + case EditCommand.COMMAND_WORD: + return prepareEdit(arguments); + + case SelectCommand.COMMAND_WORD: + return prepareSelect(arguments); + + case DeleteCommand.COMMAND_WORD: + return prepareDelete(arguments); + + case DoneCommand.COMMAND_WORD: + return prepareDone(arguments); + + case ClearCommand.COMMAND_WORD: + return new ClearCommand(); + + case FindCommand.COMMAND_WORD: + return prepareFind(arguments); + + case ListCommand.COMMAND_WORD: + return prepareList(arguments); + + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); + + case HelpCommand.COMMAND_WORD: + return prepareHelp(arguments); + + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + + default: + return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); + } + } + + /** + * Parses arguments in the context of the add task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareAdd(String args){ + String preprocessedArg = appendEnd(args.trim()); + + final Matcher nameMatcher = NAME_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + + String nameToAdd = checkEmptyAndAddDefault(nameMatcher, "name", "none"); + String dueDateToAdd = checkEmptyAndAddDefault(dueDateMatcher, "dueDate", "none"); + String addressToAdd = checkEmptyAndAddDefault(addressMatcher, "address", "none"); + String priorityToAdd = checkEmptyAndAddDefault(priorityMatcher, "priority", "1"); +// String tagsToAdd = checkEmptyAndAddDefault(tagsMatcher, "tagsArgument", ""); + + // format date if due date is specified + if (dueDateMatcher.matches()) { + dueDateToAdd = parseDueDate(dueDateToAdd); + } + + Set tagsProcessed = Collections.emptySet(); + + if (tagsMatcher.matches()) { + tagsProcessed = getTagsFromArgs(tagsMatcher.group("tagArguments")); + } + + // Validate arg string format + if (!nameMatcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + + try { + return new AddCommand( + nameToAdd, + dueDateToAdd, + addressToAdd, + priorityToAdd, + tagsProcessed + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + private String appendEnd(String args) { + return args + " z/"; + } + + private String checkEmptyAndAddDefault(Matcher matcher, String groupName, String defaultValue) { + if (matcher.matches()) { + return matcher.group(groupName); + } else { + return defaultValue; + } + } + +``` +###### /src/main/java/seedu/gtd/logic/parser/Parser.java +``` java + /** + * Extracts the new task's tags from the add command's tag arguments string. + * Merges duplicate tag strings. + */ + private static Set getTagsFromArgs(String tagArguments) { + // no tags + if (tagArguments.isEmpty()) { + return Collections.emptySet(); + } + // replace first delimiter prefix, then split + final Collection tagStrings = Arrays.asList(tagArguments.split(" ")); + return new HashSet<>(tagStrings); + } + +``` +###### /src/main/java/seedu/gtd/logic/parser/Parser.java +``` java + /** + * Parses arguments in the context of the delete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareDelete(String args) { + + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + } + + return new DeleteCommand(index.get()); + } + + private Command prepareDone(String args) { + + Optional index = parseIndex(args); + System.out.println("index at preparedone:" + index.get()); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DoneCommand.MESSAGE_USAGE)); + } + + return new DoneCommand(index.get()); + } + + /** + * Parses arguments in the context of the select task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareSelect(String args) { + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE)); + } + + return new SelectCommand(index.get()); + } + + /** + * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index. + * Returns an {@code Optional.empty()} otherwise. + */ + private Optional parseIndex(String command) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim()); + if (!matcher.matches()) { + return Optional.empty(); + } + + String index = matcher.group("targetIndex"); + if(!StringUtil.isUnsignedInteger(index)){ + return Optional.empty(); + } + return Optional.of(Integer.parseInt(index)); + + } + + /** + * Parses arguments in the context of the find task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareFind(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + String preprocessedArgs = " " + appendEnd(args.trim()); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + + Set defaultSet = new HashSet(); + + if (addressMatcher.matches()) { + String addressToBeFound = addressMatcher.group("address"); + return new FindCommand(addressToBeFound, defaultSet,"address"); + } + if (priorityMatcher.matches()) { + String priorityToBeFound = priorityMatcher.group("priority"); + return new FindCommand(priorityToBeFound, defaultSet, "priority"); + } + if (dueDateMatcher.matches()) { + String dueDateToBeFound = dueDateMatcher.group("dueDate"); + String parsedDueDateToBeFound = removeTimeOnDate(parseDueDate(dueDateToBeFound)); + return new FindCommand(parsedDueDateToBeFound, defaultSet, "dueDate"); + } + if (tagsMatcher.matches()) { + String tagsToBeFound = tagsMatcher.group("tagArguments"); + return new FindCommand(tagsToBeFound, defaultSet,"tagArguments"); + } + + // free-form search by keywords + + final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + // keywords delimited by whitespace + final String[] splitKeywords = matcher.group("keywords").split("\\s+"); + final Set keywordSet = new HashSet<>(Arrays.asList(splitKeywords)); + + final String keywords = matcher.group("keywords"); + return new FindCommand(keywords, keywordSet, "nil"); + } + +private Command prepareList(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + //String preprocessedArgs = " " + appendEnd(args.trim()); + return new ListCommand(args); +} + + /** + * Parses arguments in the context of the help command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareHelp(String args) { + //if no argument + if (args.equals("")) { + args="help"; + } + + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + return new HelpCommand(commandWord); + } +} +``` +###### /src/main/java/seedu/gtd/MainApp.java +``` java +public class MainApp extends Application { + private static final Logger logger = LogsCenter.getLogger(MainApp.class); + + public static final Version VERSION = new Version(1, 0, 0, true); + + protected Ui ui; + protected Logic logic; + protected Storage storage; + protected Model model; + protected Config config; + protected UserPrefs userPrefs; + + public MainApp() {} + + @Override + public void init() throws Exception { + logger.info("=============================[ Initializing TaskList ]==========================="); + super.init(); + + config = initConfig(getApplicationParameter("config")); + storage = new StorageManager(config.getAddressBookFilePath(), config.getUserPrefsFilePath()); + + userPrefs = initPrefs(config); + + initLogging(config); + + model = initModelManager(storage, userPrefs); + + logic = new LogicManager(model, storage); + + ui = new UiManager(logic, config, userPrefs); + + initEventsCenter(); + } + + private String getApplicationParameter(String parameterName){ + Map applicationParameters = getParameters().getNamed(); + return applicationParameters.get(parameterName); + } + + private Model initModelManager(Storage storage, UserPrefs userPrefs) { + Optional addressBookOptional; + ReadOnlyAddressBook initialData; + try { + addressBookOptional = storage.readAddressBook(); + if(!addressBookOptional.isPresent()){ + logger.info("Data file not found. Will be starting with an empty TaskList"); + } + initialData = addressBookOptional.orElse(new AddressBook()); + } catch (DataConversionException e) { + logger.warning("Data file not in the correct format. Will be starting with an empty TaskList"); + initialData = new AddressBook(); + } catch (IOException e) { + logger.warning("Problem while reading from the file. . Will be starting with an empty TaskList"); + initialData = new AddressBook(); + } + + return new ModelManager(initialData, userPrefs); + } + + private void initLogging(Config config) { + LogsCenter.init(config); + } + + protected Config initConfig(String configFilePath) { + Config initializedConfig; + String configFilePathUsed; + + configFilePathUsed = Config.DEFAULT_CONFIG_FILE; + + if(configFilePath != null) { + logger.info("Custom Config file specified " + configFilePath); + configFilePathUsed = configFilePath; + } + + logger.info("Using config file : " + configFilePathUsed); + + try { + Optional configOptional = ConfigUtil.readConfig(configFilePathUsed); + initializedConfig = configOptional.orElse(new Config()); + } catch (DataConversionException e) { + logger.warning("Config file at " + configFilePathUsed + " is not in the correct format. " + + "Using default config properties"); + initializedConfig = new Config(); + } + + //Update config file in case it was missing to begin with or there are new/unused fields + try { + ConfigUtil.saveConfig(initializedConfig, configFilePathUsed); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + return initializedConfig; + } + + protected UserPrefs initPrefs(Config config) { + assert config != null; + + String prefsFilePath = config.getUserPrefsFilePath(); + logger.info("Using prefs file : " + prefsFilePath); + + UserPrefs initializedPrefs; + try { + Optional prefsOptional = storage.readUserPrefs(); + initializedPrefs = prefsOptional.orElse(new UserPrefs()); + } catch (DataConversionException e) { + logger.warning("UserPrefs file at " + prefsFilePath + " is not in the correct format. " + + "Using default user prefs"); + initializedPrefs = new UserPrefs(); + } catch (IOException e) { + logger.warning("Problem while reading from the file. . Will be starting with an empty TaskList"); + initializedPrefs = new UserPrefs(); + } + + //Update prefs file in case it was missing to begin with or there are new/unused fields + try { + storage.saveUserPrefs(initializedPrefs); + } catch (IOException e) { + logger.warning("Failed to save config file : " + StringUtil.getDetails(e)); + } + + return initializedPrefs; + } + + private void initEventsCenter() { + EventsCenter.getInstance().registerHandler(this); + } + + @Override + public void start(Stage primaryStage) { + logger.info("Starting TaskList " + MainApp.VERSION); + ui.start(primaryStage); + } + + @Override + public void stop() { + logger.info("============================ [ Stopping Task List ] ============================="); + ui.stop(); + try { + storage.saveUserPrefs(userPrefs); + } catch (IOException e) { + logger.severe("Failed to save preferences " + StringUtil.getDetails(e)); + } + Platform.exit(); + System.exit(0); + } + + @Subscribe + public void handleExitAppRequestEvent(ExitAppRequestEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + this.stop(); + } + + public static void main(String[] args) { + launch(args); + } +} +``` +###### /src/main/java/seedu/gtd/model/AddressBook.java +``` java + private final UniqueTaskList tasks; + private final UniqueTagList tags; + + { + tasks = new UniqueTaskList(); + tags = new UniqueTagList(); + } + + public AddressBook() {} + + /** + * Tasks and Tags are copied into this addressbook + */ + public AddressBook(ReadOnlyAddressBook toBeCopied) { + this(toBeCopied.getUniqueTaskList(), toBeCopied.getUniqueTagList()); + System.out.println("start with first method"); + } + + /** + * Tasks and Tags are copied into this addressbook + */ + public AddressBook(UniqueTaskList tasks, UniqueTagList tags) { + resetData(tasks.getInternalList(), tags.getInternalList()); + System.out.println("start with second method"); + } + + public static ReadOnlyAddressBook getEmptyAddressBook() { + return new AddressBook(); + } + +//// list overwrite operations + + public ObservableList getTasks() { + return tasks.getInternalList(); + } + + public void setTasks(List tasks) { + this.tasks.getInternalList().setAll(tasks); + } + + public void setTags(Collection tags) { + this.tags.getInternalList().setAll(tags); + } + + public void resetData(Collection newTasks, Collection newTags) { + setTasks(newTasks.stream().map(Task::new).collect(Collectors.toList())); + setTags(newTags); + } + + public void resetData(ReadOnlyAddressBook newData) { + resetData(newData.getTaskList(), newData.getTagList()); + } + +//// task-level operations + + /** + * Adds a task to the address book. + * Also checks the new task's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the task to point to those in {@link #tags}. + * + * @throws UniqueTaskList.DuplicateTaskException if an equivalent task already exists. + */ + public void addTask(Task t) throws UniqueTaskList.DuplicateTaskException { + syncTagsWithMasterList(t); + tasks.add(t); + } + +``` +###### /src/main/java/seedu/gtd/model/AddressBook.java +``` java + /** + * Ensures that every tag in this task: + * - exists in the master list {@link #tags} + * - points to a Tag object in the master list + */ + private void syncTagsWithMasterList(Task t) { + final UniqueTagList taskTags = t.getTags(); + tags.mergeFrom(taskTags); + + // Create map with values = tag object references in the master list + final Map masterTagObjects = new HashMap<>(); + for (Tag tag : tags) { + masterTagObjects.put(tag, tag); + } + + // Rebuild the list of task tags using references from the master list + final Set commonTagReferences = new HashSet<>(); + for (Tag tag : taskTags) { + commonTagReferences.add(masterTagObjects.get(tag)); + } + t.setTags(new UniqueTagList(commonTagReferences)); + } + + public boolean removeTask(ReadOnlyTask key) throws UniqueTaskList.TaskNotFoundException { + if (tasks.remove(key)) { + return true; + } else { + throw new UniqueTaskList.TaskNotFoundException(); + } + } + + public void doneTask(int index, Task target) throws TaskNotFoundException { + System.out.println("in addressbook"); + tasks.done(index, target); + } + +//// tag-level operations + + public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { + tags.add(t); + } + +//// util methods + + @Override + public String toString() { + return tasks.getInternalList().size() + " tasks, " + tags.getInternalList().size() + " tags"; + // TODO: refine later + } + + @Override + public List getTaskList() { + return Collections.unmodifiableList(tasks.getInternalList()); + } + + @Override + public List getTagList() { + return Collections.unmodifiableList(tags.getInternalList()); + } + + @Override + public UniqueTaskList getUniqueTaskList() { + return this.tasks; + } + + @Override + public UniqueTagList getUniqueTagList() { + return this.tags; + } + + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddressBook // instanceof handles nulls + && this.tasks.equals(((AddressBook) other).tasks) + && this.tags.equals(((AddressBook) other).tags)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(tasks, tags); + } +} +``` +###### /src/main/java/seedu/gtd/model/ModelManager.java +``` java + + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private AddressBook addressBook; + private final FilteredList filteredTasks; + private AddressBook previousAddressBook; + + /** + * Initializes a ModelManager with the given AddressBook + * AddressBook and its variables should not be null + */ + public ModelManager(AddressBook src, UserPrefs userPrefs) { + super(); + assert src != null; + assert userPrefs != null; + + logger.fine("Initializing with address book: " + src + " and user prefs " + userPrefs); + + addressBook = new AddressBook(src); + filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new AddressBook(addressBook); + } + + public ModelManager() { + this(new AddressBook(), new UserPrefs()); + } + + public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { + addressBook = new AddressBook(initialData); + filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new AddressBook(addressBook); + } + + private void resetData(ReadOnlyAddressBook newData) { + addressBook.resetData(newData); + indicateAddressBookChanged(); + } + + @Override + public ReadOnlyAddressBook getAddressBook() { + return addressBook; + } + + /** Raises an event to indicate the model has changed */ + private void indicateAddressBookChanged() { + raise(new AddressBookChangedEvent(addressBook)); + } + + private void savePreviousAddressBook() { + previousAddressBook = new AddressBook(addressBook); + } + + @Override + public void undoAddressBookChange() { + resetData(previousAddressBook); + } + + @Override + public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.removeTask(target); + indicateAddressBookChanged(); + } + + @Override + public synchronized void doneTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + System.out.println("in model manager"); + addressBook.doneTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + + @Override + public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskException { + savePreviousAddressBook(); + addressBook.addTask(task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + +``` +###### /src/main/java/seedu/gtd/model/ModelManager.java +``` java + //=========== Filtered Task List Accessors =============================================================== + + @Override + public UnmodifiableObservableList getFilteredTaskList() { + return new UnmodifiableObservableList<>(filteredTasks); + } + + @Override + public void updateFilteredListToShowAll() { + updateFilteredListToShowAll(new PredicateExpression(new RemoveDoneQualifier())); + System.out.println("show all"); + } + + private void updateFilteredListToShowAll(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowRemoved() { + updateFilteredListToShowRemoved(new PredicateExpression(new DoneQualifier())); + System.out.println("show done list"); + } + + private void updateFilteredListToShowRemoved(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredTaskList(Set keywordSet) { + updateFilteredTaskList(new PredicateExpression(new NameQualifier(keywordSet))); + } + + @Override + public void updateFilteredTaskList(String keywords, Set keywordSet){ + updateFilteredTaskList(new PredicateExpression(new orderedNameQualifier(keywords, keywordSet))); + } + + @Override + public void updateFilteredTaskList(String keywords, String cmd) { + updateFilteredTaskList(new PredicateExpression(new otherFieldsQualifier(keywords, cmd))); + } + + private void updateFilteredTaskList(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + //========== Inner classes/interfaces used for filtering ================================================== + + interface Expression { + boolean satisfies(ReadOnlyTask task); + String toString(); + } + + private class PredicateExpression implements Expression { + + private final Qualifier qualifier; + + PredicateExpression(Qualifier qualifier) { + this.qualifier = qualifier; + } + + @Override + public boolean satisfies(ReadOnlyTask task) { + return qualifier.run(task); + } + + @Override + public String toString() { + return qualifier.toString(); + } + } + + interface Qualifier { + boolean run(ReadOnlyTask task); + String toString(); + } + + private class NameQualifier implements Qualifier { + protected Set keywordSet; + + NameQualifier(Set keywordSet) { + this.keywordSet = keywordSet; + } + + @Override + public boolean run(ReadOnlyTask task) { + return keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); + } + + @Override + public String toString() { + return "name=" + String.join(", ", keywordSet); + } + } + + private class otherFieldsQualifier implements Qualifier { + protected String nameKeyWords; + protected String cmd; + + otherFieldsQualifier(String keywords, String cmd) { + this.nameKeyWords = keywords; + this.cmd = cmd; + } + + @Override + public boolean run(ReadOnlyTask task) { + if (cmd == "address") { + System.out.println("finding address.."); + String address = task.getAddress().toString().toLowerCase(); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + return addressMatch; + } else if (cmd == "priority") { + System.out.println("finding priority.."); + String priority = task.getPriority().toString(); + boolean priorityMatch = priority.contains(nameKeyWords); + return priorityMatch; + } else if (cmd == "dueDate") { + System.out.println("finding dueDate.."); + String dueDate = task.getDueDate().toString(); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + return dueDateMatch; + } else if (cmd == "tagArguments") { + System.out.println("finding tags.. "); + UniqueTagList tagsList = task.getTags(); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + return tagsMatch; + } + + // cmd == "nil" + + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + String priority = task.getPriority().toString(); + String address = task.getAddress().toString().toLowerCase(); + String dueDate = task.getDueDate().toString(); + UniqueTagList tagsList = task.getTags(); + + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + boolean priorityMatch = priority.contains(nameKeyWords); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + boolean eachWordMatch = false; + + String[] eachWord = nameKeyWords.split(" "); + for (String word : eachWord) { + System.out.println("each: " + word); + eachWordMatch = eachWordMatch || taskFullNameLowerCase.contains(word.toLowerCase()); + } + + return eachWordMatch || nameMatch || addressMatch || priorityMatch || dueDateMatch || tagsMatch; + } + } + + private class orderedNameQualifier extends NameQualifier implements Qualifier { + private String nameKeyWords; + + orderedNameQualifier(String keywords, Set keywordSet) { + super(keywordSet); + this.nameKeyWords = keywords; + } + + @Override + public boolean run(ReadOnlyTask task) { + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + + boolean eachWordMatch = keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); + return eachWordMatch && nameMatch; + } + } + + // to check and return a list of tasks that are already done + private class DoneQualifier implements Qualifier { + + DoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + return task.getisDone(); + } + } + + // default display tasks that are not yet done + private class RemoveDoneQualifier implements Qualifier { + + RemoveDoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + System.out.println(task.getName()); + return !task.getisDone(); + } + } +} +``` +###### /src/main/java/seedu/gtd/model/task/UniqueTaskList.java +``` java + /** + * Signals that an operation would have violated the 'no duplicates' property of the list. + */ + public static class DuplicateTaskException extends DuplicateDataException { + protected DuplicateTaskException() { + super("Operation would result in duplicate tasks"); + } + } + + /** + * Signals that an operation targeting a specified task in the list would fail because + * there is no such matching task in the list. + */ + public static class TaskNotFoundException extends Exception {} + + private final ObservableList internalList = FXCollections.observableArrayList(); + + /** + * Constructs empty TaskList. + */ + public UniqueTaskList() {} + + /** + * Returns true if the list contains an equivalent task as the given argument. + */ + public boolean contains(ReadOnlyTask toCheck) { + assert toCheck != null; + return internalList.contains(toCheck); + } + + /** + * Adds a task to the list. + * + * @throws DuplicateTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(Task toAdd) throws DuplicateTaskException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateTaskException(); + } + internalList.add(toAdd); + } + +``` +###### /src/main/java/seedu/gtd/model/task/UniqueTaskList.java +``` java + /** + * Removes the equivalent task from the list. + * + * @throws TaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyTask toRemove) throws TaskNotFoundException { + assert toRemove != null; + final boolean taskFoundAndDeleted = internalList.remove(toRemove); + if (!taskFoundAndDeleted) { + throw new TaskNotFoundException(); + } + return taskFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueTaskList // instanceof handles nulls + && this.internalList.equals( + ((UniqueTaskList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } +} +``` +###### /src/test/java/seedu/gtd/logic/LogicManagerTest.java +``` java + + /** + * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule + */ + @Rule + public TemporaryFolder saveFolder = new TemporaryFolder(); + + private Model model; + private Logic logic; + + //These are for checking the correctness of the events raised + private ReadOnlyAddressBook latestSavedAddressBook; + private boolean helpShown; + private int targetedJumpIndex; + + @Subscribe + private void handleLocalModelChangedEvent(AddressBookChangedEvent abce) { + latestSavedAddressBook = new AddressBook(abce.data); + } + + @Subscribe + private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) { + helpShown = true; + } + + @Subscribe + private void handleJumpToListRequestEvent(JumpToListRequestEvent je) { + targetedJumpIndex = je.targetIndex; + } + + @Before + public void setup() { + model = new ModelManager(); + String tempAddressBookFile = saveFolder.getRoot().getPath() + "TempAddressBook.xml"; + String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json"; + logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile)); + EventsCenter.getInstance().registerHandler(this); + + latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before. + helpShown = false; + targetedJumpIndex = -1; // non yet + } + + @After + public void teardown() { + EventsCenter.clearSubscribers(); + } + + @Test + public void execute_invalid() throws Exception { + String invalidCommand = " "; + assertCommandBehavior(invalidCommand, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + /** + * Executes the command and confirms that the result message is correct. + * Both the 'address book' and the 'last shown list' are expected to be empty. + * @see #assertCommandBehavior(String, String, ReadOnlyAddressBook, List) + */ + private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { + assertCommandBehavior(inputCommand, expectedMessage, new AddressBook(), Collections.emptyList()); + } + + /** + * Executes the command and confirms that the result message is correct and + * also confirms that the following three parts of the LogicManager object's state are as expected:
+ * - the internal address book data are same as those in the {@code expectedAddressBook}
+ * - the backing list shown by UI matches the {@code shownList}
+ * - {@code expectedAddressBook} was saved to the storage file.
+ */ + private void assertCommandBehavior(String inputCommand, String expectedMessage, + ReadOnlyAddressBook expectedAddressBook, + List expectedShownList) throws Exception { + + //Execute the command + CommandResult result = logic.execute(inputCommand); + System.out.println(inputCommand); + + //Confirm the ui display elements should contain the right data + System.out.println(result.feedbackToUser); + System.out.println(expectedMessage); + assertEquals(expectedMessage, result.feedbackToUser); + System.out.println("correct message"); + assertEquals(expectedShownList, model.getFilteredTaskList()); + System.out.println("correct data in UI"); + + //Confirm the state of data (saved and in-memory) is as expected + assertEquals(expectedAddressBook, model.getAddressBook()); + assertEquals(expectedAddressBook, latestSavedAddressBook); + } + + + @Test + public void execute_unknownCommandWord() throws Exception { + String unknownCommand = "uicfhmowqewca"; + assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND); + } + +``` +###### /src/test/java/seedu/gtd/logic/LogicManagerTest.java +``` java + @Test + public void execute_exit() throws Exception { + assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT); + } + + @Test + public void execute_clear() throws Exception { + TestDataHelper helper = new TestDataHelper(); + model.addTask(helper.generateTask(1)); + model.addTask(helper.generateTask(2)); + model.addTask(helper.generateTask(3)); + + assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new AddressBook(), Collections.emptyList()); + } + + @Test + public void execute_add_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); + assertCommandBehavior( + "add ", expectedMessage); + } + + + @Test + public void execute_add_invalidTaskData() throws Exception { + assertCommandBehavior( + "add []\\[;] d/12345 a/valid, address p/1", Name.MESSAGE_NAME_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/not_numbers a/valid, address p/2", DueDate.MESSAGE_DUEDATE_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/12345 a/valid, address p/not_priority_numbers", Priority.MESSAGE_PRIORITY_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/12345 a/valid, address p/5 t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); + + } + + @Test + public void execute_add_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.adam(); + Task dateChanged = helper.adamChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(dateChanged); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, dateChanged), + expectedAB, + expectedAB.getTaskList()); + + } + + @Test + public void execute_add_optional_successful() throws Exception { + + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task intendedResult = helper.optionalAddressDateChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(intendedResult); + String optionalAddressCmd = "add clean room d/noon p/3 t/tag1"; + + assertCommandBehavior(optionalAddressCmd, + String.format(AddCommand.MESSAGE_SUCCESS, intendedResult), + expectedAB, + expectedAB.getTaskList()); + } + + @Test + public void execute_addDuplicate_notAllowed() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.adam(); + Task changedDate = helper.adamChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(changedDate); + + // setup starting state + model.addTask(changedDate); // task already in internal address book + + // execute command and verify result + assertCommandBehavior( + helper.generateAddCommand(toBeAdded), + AddCommand.MESSAGE_DUPLICATE_TASK, + expectedAB, + expectedAB.getTaskList()); + + } + + /* + @Test + public void execute_edit_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeEdited = helper.adam(); + AddressBook expectedAB = helper.generateAddressBook(2); + expectedAB.editTask(1, toBeEdited); + + // execute command and verify result + assertCommandBehavior(helper.generateEditCommand(toBeEdited), + String.format(EditCommand.MESSAGE_EDIT_TASK_SUCCESS, toBeEdited), + expectedAB, + expectedAB.getTaskList()); + } + */ + + + @Test + public void execute_list_showsAllTasks() throws Exception { + // prepare expectations + TestDataHelper helper = new TestDataHelper(); + AddressBook expectedAB = helper.generateAddressBook(2); + List expectedList = expectedAB.getTaskList(); + + // prepare address book state + helper.addToModel(model, 2); + + assertCommandBehavior("list", + ListCommand.MESSAGE_SUCCESS, + expectedAB, + expectedList); + } + + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { + assertCommandBehavior(commandWord , expectedMessage); //index missing + assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0 + assertCommandBehavior(commandWord + " not_a_number", expectedMessage); + } + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { + String expectedMessage = MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + TestDataHelper helper = new TestDataHelper(); + List taskList = helper.generateTaskList(2); + + // set AB state to 2 tasks + model.clearTaskList(); + for (Task p : taskList) { + model.addTask(p); + } + + assertCommandBehavior(commandWord + " 3", expectedMessage, model.getAddressBook(), taskList); + } + + @Test + public void execute_selectInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("select", expectedMessage); + } + + @Test + public void execute_selectIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("select"); + } + + @Test + public void execute_select_jumpsToCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeTasks = helper.generateTaskList(3); + + AddressBook expectedAB = helper.generateAddressBook(threeTasks); + helper.addToModel(model, threeTasks); + + assertCommandBehavior("select 2", + String.format(SelectCommand.MESSAGE_SELECT_TASK_SUCCESS, 2), + expectedAB, + expectedAB.getTaskList()); + assertEquals(1, targetedJumpIndex); + assertEquals(model.getFilteredTaskList().get(1), threeTasks.get(1)); + } + + + @Test + public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage); + } + + @Test + public void execute_deleteIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("delete"); + } + + @Test + public void execute_delete_removesCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeTasks = helper.generateTaskList(3); + + AddressBook expectedAB = helper.generateAddressBook(threeTasks); + expectedAB.removeTask(threeTasks.get(1)); + helper.addToModel(model, threeTasks); + + assertCommandBehavior("delete 2", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, threeTasks.get(1)), + expectedAB, + expectedAB.getTaskList()); + } + + + @Test + public void execute_find_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); + assertCommandBehavior("find ", expectedMessage); + } + + @Test + public void execute_find_onlyMatchesFullWordsInNames() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + Task pTarget2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + Task p1 = helper.generateTaskWithName("KE Y"); + Task p2 = helper.generateTaskWithName("KEYKEYKEY sduauo"); + + List fourTasks = helper.generateTaskList(p1, pTarget1, p2, pTarget2); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = helper.generateTaskList(pTarget1, pTarget2); + helper.addToModel(model, fourTasks); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + @Test + public void execute_find_isNotCaseSensitive() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task p1 = helper.generateTaskWithName("bla bla KEY bla"); + Task p2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + Task p3 = helper.generateTaskWithName("key key"); + Task p4 = helper.generateTaskWithName("KEy sduauo"); + + List fourTasks = helper.generateTaskList(p3, p1, p4, p2); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = fourTasks; + helper.addToModel(model, fourTasks); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + @Test + public void execute_find_matchesIfAnyKeywordPresent() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + Task pTarget2 = helper.generateTaskWithName("bla rAnDoM bla bceofeia"); + Task pTarget3 = helper.generateTaskWithName("key key"); + Task p1 = helper.generateTaskWithName("sduauo"); + + List fourTasks = helper.generateTaskList(pTarget1, p1, pTarget2, pTarget3); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = helper.generateTaskList(pTarget1, pTarget2, pTarget3); + helper.addToModel(model, fourTasks); + + String keywords = "key rAnDoM"; + TestFindHelper findhelper = new TestFindHelper(); + + assertCommandBehavior("find " + keywords, + String.format(findhelper.generateCorrectResultIfExactPhraseNotFound(keywords, expectedList.size())), + expectedAB, + expectedList); + } + + class TestFindHelper{ + + String generateCorrectResultIfExactPhraseNotFound(String keywords, int expectedListSize) { + String task_tasks = (expectedListSize == 1) ? "task" : "tasks"; + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + expectedListSize + " " + task_tasks + " containing the keywords entered instead."; + return MESSAGE_IF_EXACT_PHRASE_NOT_FOUND; + } + } + + + /** + * A utility class to generate test data. + */ + class TestDataHelper{ + + Task adam() throws Exception { + Name name = new Name("Pick up laundry"); + DueDate privateDueDate = new DueDate("noon"); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("1"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, privateDueDate, address, privatePriority, tags); + } + Task adamChanged() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + Name name = new Name("Pick up laundry"); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("1"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, privateDueDate, address, privatePriority, tags); + } + + + Task optionalAddressDateChanged() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + Name name = new Name("clean room"); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("none"); + Priority privatePriority = new Priority("3"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, privateDueDate, address, privatePriority, tags); + } + + /** + * Generates a valid task using the given seed. + * Running this function with the same parameter values guarantees the returned task will have the same state. + * Each unique seed will generate a unique Task object. + * + * @param seed used to generate the task data field values + */ + Task generateTask(int seed) throws Exception { + return new Task( + new Name("Task " + seed), + new DueDate("" + Math.abs(seed)), + new Address(seed + ", -address"), + new Priority("1 " + seed), + new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1))) + ); + } + + /** Generates the correct add command based on the task given */ + String generateAddCommand(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + + cmd.append(p.getName().toString()); + cmd.append(" d/").append(p.getDueDate()); + cmd.append(" a/").append(p.getAddress()); + cmd.append(" p/").append(p.getPriority()); + + UniqueTagList tags = p.getTags(); + for(Tag t: tags){ + cmd.append(" t/").append(t.tagName); + } + + return cmd.toString(); + } + + /** Generates the correct add command based on the task given */ + String generateEditCommand(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("edit "); + cmd.append(" d/").append(p.getDueDate()); + + return cmd.toString(); + } + + /** + * Generates an AddressBook with auto-generated tasks. + */ + AddressBook generateAddressBook(int numGenerated) throws Exception{ + AddressBook addressBook = new AddressBook(); + addToAddressBook(addressBook, numGenerated); + return addressBook; + } + + /** + * Generates an AddressBook based on the list of Tasks given. + */ + AddressBook generateAddressBook(List tasks) throws Exception{ + AddressBook addressBook = new AddressBook(); + addToAddressBook(addressBook, tasks); + return addressBook; + } + + /** + * Adds auto-generated Task objects to the given AddressBook + * @param addressBook The AddressBook to which the Tasks will be added + */ + void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{ + addToAddressBook(addressBook, generateTaskList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given AddressBook + */ + void addToAddressBook(AddressBook addressBook, List tasksToAdd) throws Exception{ + for(Task p: tasksToAdd){ + addressBook.addTask(p); + } + } + + /** + * Adds auto-generated Task objects to the given model + * @param model The model to which the Tasks will be added + */ + void addToModel(Model model, int numGenerated) throws Exception{ + addToModel(model, generateTaskList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given model + */ + void addToModel(Model model, List tasksToAdd) throws Exception{ + for(Task p: tasksToAdd){ + model.addTask(p); + } + } + + /** + * Generates a list of Tasks based on the flags. + */ + List generateTaskList(int numGenerated) throws Exception{ + List tasks = new ArrayList<>(); + for(int i = 1; i <= numGenerated; i++){ + tasks.add(generateTask(i)); + } + return tasks; + } + + List generateTaskList(Task... tasks) { + return Arrays.asList(tasks); + } + + /** + * Generates a Task object with given name. Other fields will have some dummy values. + */ + Task generateTaskWithName(String name) throws Exception { + return new Task( + new Name(name), + new DueDate("1"), + new Address("House of 1"), + new Priority("1"), + new UniqueTagList(new Tag("tag")) + ); + } + } +} +``` +###### /src/test/java/seedu/gtd/testutil/TestUtil.java +``` java + + public static String LS = System.lineSeparator(); + + public static void assertThrows(Class expected, Runnable executable) { + try { + executable.run(); + } + catch (Throwable actualException) { + if (!actualException.getClass().isAssignableFrom(expected)) { + String message = String.format("Expected thrown: %s, actual: %s", expected.getName(), + actualException.getClass().getName()); + throw new AssertionFailedError(message); + } else return; + } + throw new AssertionFailedError( + String.format("Expected %s to be thrown, but nothing was thrown.", expected.getName())); + } + + /** + * Folder used for temp files created during testing. Ignored by Git. + */ + public static String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); + + public static final Task[] sampleTaskData = getSampleTaskData(); + + private static Task[] getSampleTaskData() { + try { + return new Task[]{ + new Task(new Name("Ali Muster"), new DueDate("9482424"), new Address("4th street"), new Priority("4"), new UniqueTagList()), + new Task(new Name("Boris Mueller"), new DueDate("87249245"), new Address("81th street"), new Priority("3"), new UniqueTagList()), + new Task(new Name("Carl Kurz"), new DueDate("95352563"), new Address("wall street"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Daniel Meier"), new DueDate("87652533"), new Address("10th street"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Elle Meyer"), new DueDate("9482224"), new Address("michegan ave"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Fiona Kunz"), new DueDate("9482427"), new Address("little tokyo"), new Priority("1"), new UniqueTagList()), + new Task(new Name("George Best"), new DueDate("9482442"), new Address("4th street"), new Priority("4"), new UniqueTagList()), + new Task(new Name("Hoon Meier"), new DueDate("8482424"), new Address("little india"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Ida Mueller"), new DueDate("8482131"), new Address("chicago ave"), new Priority("1"), new UniqueTagList()) + }; + } catch (IllegalValueException e) { + assert false; + //not possible + return null; + } + } + + public static final Tag[] sampleTagData = getSampleTagData(); + + private static Tag[] getSampleTagData() { + try { + return new Tag[]{ + new Tag("relatives"), + new Tag("friends") + }; + } catch (IllegalValueException e) { + assert false; + return null; + //not possible + } + } + + public static List generateSampleTaskData() { + return Arrays.asList(sampleTaskData); + } + + /** + * Appends the file name to the sandbox folder path. + * Creates the sandbox folder if it doesn't exist. + * @param fileName + * @return + */ + public static String getFilePathInSandboxFolder(String fileName) { + try { + FileUtil.createDirs(new File(SANDBOX_FOLDER)); + } catch (IOException e) { + throw new RuntimeException(e); + } + return SANDBOX_FOLDER + fileName; + } + + public static void createDataFileWithSampleData(String filePath) { + createDataFileWithData(generateSampleStorageAddressBook(), filePath); + } + + public static void createDataFileWithData(T data, String filePath) { + try { + File saveFileForTesting = new File(filePath); + FileUtil.createIfMissing(saveFileForTesting); + XmlUtil.saveDataToFile(saveFileForTesting, data); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String... s) { + createDataFileWithSampleData(TestApp.SAVE_LOCATION_FOR_TESTING); + } + + public static AddressBook generateEmptyAddressBook() { + return new AddressBook(new UniqueTaskList(), new UniqueTagList()); + } + + public static XmlSerializableAddressBook generateSampleStorageAddressBook() { + return new XmlSerializableAddressBook(generateEmptyAddressBook()); + } + + /** + * Tweaks the {@code keyCodeCombination} to resolve the {@code KeyCode.SHORTCUT} to their + * respective platform-specific keycodes + */ + public static KeyCode[] scrub(KeyCodeCombination keyCodeCombination) { + List keys = new ArrayList<>(); + if (keyCodeCombination.getAlt() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.ALT); + } + if (keyCodeCombination.getShift() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.SHIFT); + } + if (keyCodeCombination.getMeta() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.META); + } + if (keyCodeCombination.getControl() == KeyCombination.ModifierValue.DOWN) { + keys.add(KeyCode.CONTROL); + } + keys.add(keyCodeCombination.getCode()); + return keys.toArray(new KeyCode[]{}); + } + + public static boolean isHeadlessEnvironment() { + String headlessProperty = System.getProperty("testfx.headless"); + return headlessProperty != null && headlessProperty.equals("true"); + } + + public static void captureScreenShot(String fileName) { + File file = GuiTest.captureScreenshot(); + try { + Files.copy(file, new File(fileName + ".png")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String descOnFail(Object... comparedObjects) { + return "Comparison failed \n" + + Arrays.asList(comparedObjects).stream() + .map(Object::toString) + .collect(Collectors.joining("\n")); + } + + public static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException{ + field.setAccessible(true); + // remove final modifier from field + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + // ~Modifier.FINAL is used to remove the final modifier from field so that its value is no longer + // final and can be changed + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + field.set(null, newValue); + } + + public static void initRuntime() throws TimeoutException { + FxToolkit.registerPrimaryStage(); + FxToolkit.hideStage(); + } + + public static void tearDownRuntime() throws Exception { + FxToolkit.cleanupStages(); + } + + /** + * Gets private method of a class + * Invoke the method using method.invoke(objectInstance, params...) + * + * Caveat: only find method declared in the current Class, not inherited from supertypes + */ + public static Method getPrivateMethod(Class objectClass, String methodName) throws NoSuchMethodException { + Method method = objectClass.getDeclaredMethod(methodName); + method.setAccessible(true); + return method; + } + + public static void renameFile(File file, String newFileName) { + try { + Files.copy(file, new File(newFileName)); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + + /** + * Gets mid point of a node relative to the screen. + * @param node + * @return + */ + public static Point2D getScreenMidPoint(Node node) { + double x = getScreenPos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; + double y = getScreenPos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; + return new Point2D(x,y); + } + + /** + * Gets mid point of a node relative to its scene. + * @param node + * @return + */ + public static Point2D getSceneMidPoint(Node node) { + double x = getScenePos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; + double y = getScenePos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; + return new Point2D(x,y); + } + + /** + * Gets the bound of the node relative to the parent scene. + * @param node + * @return + */ + public static Bounds getScenePos(Node node) { + return node.localToScene(node.getBoundsInLocal()); + } + + public static Bounds getScreenPos(Node node) { + return node.localToScreen(node.getBoundsInLocal()); + } + + public static double getSceneMaxX(Scene scene) { + return scene.getX() + scene.getWidth(); + } + + public static double getSceneMaxY(Scene scene) { + return scene.getX() + scene.getHeight(); + } + + public static Object getLastElement(List list) { + return list.get(list.size() - 1); + } + + /** + * Removes a subset from the list of tasks. + * @param tasks The list of tasks + * @param tasksToRemove The subset of tasks. + * @return The modified tasks after removal of the subset from tasks. + */ + public static TestTask[] removeTasksFromList(final TestTask[] tasks, TestTask... tasksToRemove) { + List listOfTasks = asList(tasks); + listOfTasks.removeAll(asList(tasksToRemove)); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + + + /** + * Returns a copy of the list with the task at specified index removed. + * @param list original list to copy from + * @param targetIndexInOneIndexedFormat e.g. if the first element to be removed, 1 should be given as index. + */ + public static TestTask[] removeTaskFromList(final TestTask[] list, int targetIndexInOneIndexedFormat) { + return removeTasksFromList(list, list[targetIndexInOneIndexedFormat-1]); + } + + /** + * Replaces tasks[i] with a task. + * @param tasks The array of tasks. + * @param task The replacement task + * @param index The index of the task to be replaced. + * @return + */ + public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task, int index) { + tasks[index] = task; + return tasks; + } + + /** + * Appends tasks to the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. + */ + public static TestTask[] addTasksToList(final TestTask[] tasks, TestTask... tasksToAdd) { + List listOfTasks = asList(tasks); + listOfTasks.addAll(asList(tasksToAdd)); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + +``` +###### /src/test/java/seedu/gtd/testutil/TestUtil.java +``` java + + private static List asList(T[] objs) { + List list = new ArrayList<>(); + for(T obj : objs) { + list.add(obj); + } + return list; + } + + public static boolean compareCardAndTask(TaskCardHandle card, ReadOnlyTask task) { + return card.isSameTask(task); + } + + public static Tag[] getTagList(String tags) { + + if (tags.equals("")) { + return new Tag[]{}; + } + + final String[] split = tags.split(", "); + + final List collect = Arrays.asList(split).stream().map(e -> { + try { + return new Tag(e.replaceFirst("Tag: ", "")); + } catch (IllegalValueException e1) { + //not possible + assert false; + return null; + } + }).collect(Collectors.toList()); + + return collect.toArray(new Tag[split.length]); + } + +} +``` diff --git a/libs/natty-0.7.jar b/libs/natty-0.7.jar new file mode 100644 index 000000000000..c4767a3d7357 Binary files /dev/null and b/libs/natty-0.7.jar differ diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java deleted file mode 100644 index 1deb3a1e4695..000000000000 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ /dev/null @@ -1,13 +0,0 @@ -package seedu.address.commons.core; - -/** - * Container for user visible messages. - */ -public class Messages { - - public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; - public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; - public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; - public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; - -} diff --git a/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java b/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java deleted file mode 100644 index 95377b326fa6..000000000000 --- a/src/main/java/seedu/address/commons/events/ui/PersonPanelSelectionChangedEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package seedu.address.commons.events.ui; - -import seedu.address.commons.events.BaseEvent; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * Represents a selection change in the Person List Panel - */ -public class PersonPanelSelectionChangedEvent extends BaseEvent { - - - private final ReadOnlyPerson newSelection; - - public PersonPanelSelectionChangedEvent(ReadOnlyPerson newSelection){ - this.newSelection = newSelection; - } - - @Override - public String toString() { - return this.getClass().getSimpleName(); - } - - public ReadOnlyPerson getNewSelection() { - return newSelection; - } -} diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java deleted file mode 100644 index 2860a9ab2a85..000000000000 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import java.util.HashSet; -import java.util.Set; - -/** - * Adds a person to the address book. - */ -public class AddCommand extends Command { - - public static final String COMMAND_WORD = "add"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. " - + "Parameters: NAME p/PHONE e/EMAIL a/ADDRESS [t/TAG]...\n" - + "Example: " + COMMAND_WORD - + " John Doe p/98765432 e/johnd@gmail.com a/311, Clementi Ave 2, #02-25 t/friends t/owesMoney"; - - public static final String MESSAGE_SUCCESS = "New person added: %1$s"; - public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; - - private final Person toAdd; - - /** - * Convenience constructor using raw values. - * - * @throws IllegalValueException if any of the raw values are invalid - */ - public AddCommand(String name, String phone, String email, String address, Set tags) - throws IllegalValueException { - final Set tagSet = new HashSet<>(); - for (String tagName : tags) { - tagSet.add(new Tag(tagName)); - } - this.toAdd = new Person( - new Name(name), - new Phone(phone), - new Email(email), - new Address(address), - new UniqueTagList(tagSet) - ); - } - - @Override - public CommandResult execute() { - assert model != null; - try { - model.addPerson(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); - } catch (UniquePersonList.DuplicatePersonException e) { - return new CommandResult(MESSAGE_DUPLICATE_PERSON); - } - - } - -} diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java deleted file mode 100644 index 1bfebe8912a8..000000000000 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ /dev/null @@ -1,50 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.commons.core.Messages; -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList.PersonNotFoundException; - -/** - * Deletes a person identified using it's last displayed index from the address book. - */ -public class DeleteCommand extends Command { - - public static final String COMMAND_WORD = "delete"; - - public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Deletes the person identified by the index number used in the last person listing.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; - - public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; - - public final int targetIndex; - - public DeleteCommand(int targetIndex) { - this.targetIndex = targetIndex; - } - - - @Override - public CommandResult execute() { - - UnmodifiableObservableList lastShownList = model.getFilteredPersonList(); - - if (lastShownList.size() < targetIndex) { - indicateAttemptToExecuteIncorrectCommand(); - return new CommandResult(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - ReadOnlyPerson personToDelete = lastShownList.get(targetIndex - 1); - - try { - model.deletePerson(personToDelete); - } catch (PersonNotFoundException pnfe) { - assert false : "The target person cannot be missing"; - } - - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); - } - -} diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java deleted file mode 100644 index 1d61bf6cc857..000000000000 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ /dev/null @@ -1,30 +0,0 @@ -package seedu.address.logic.commands; - -import java.util.Set; - -/** - * Finds and lists all persons in address book whose name contains any of the argument keywords. - * Keyword matching is case sensitive. - */ -public class FindCommand extends Command { - - public static final String COMMAND_WORD = "find"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of " - + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; - - private final Set keywords; - - public FindCommand(Set keywords) { - this.keywords = keywords; - } - - @Override - public CommandResult execute() { - model.updateFilteredPersonList(keywords); - return new CommandResult(getMessageForPersonListShownSummary(model.getFilteredPersonList().size())); - } - -} diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java deleted file mode 100644 index 65af96940242..000000000000 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package seedu.address.logic.commands; - - -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.ui.ShowHelpRequestEvent; - -/** - * Format full help instructions for every command for display. - */ -public class HelpCommand extends Command { - - public static final String COMMAND_WORD = "help"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" - + "Example: " + COMMAND_WORD; - - public static final String SHOWING_HELP_MESSAGE = "Opened help window."; - - public HelpCommand() {} - - @Override - public CommandResult execute() { - EventsCenter.getInstance().post(new ShowHelpRequestEvent()); - return new CommandResult(SHOWING_HELP_MESSAGE); - } -} diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java deleted file mode 100644 index 9bdd457a1b01..000000000000 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ /dev/null @@ -1,20 +0,0 @@ -package seedu.address.logic.commands; - - -/** - * Lists all persons in the address book to the user. - */ -public class ListCommand extends Command { - - public static final String COMMAND_WORD = "list"; - - public static final String MESSAGE_SUCCESS = "Listed all persons"; - - public ListCommand() {} - - @Override - public CommandResult execute() { - model.updateFilteredListToShowAll(); - return new CommandResult(MESSAGE_SUCCESS); - } -} diff --git a/src/main/java/seedu/address/logic/commands/SelectCommand.java b/src/main/java/seedu/address/logic/commands/SelectCommand.java deleted file mode 100644 index 9ca0551f1951..000000000000 --- a/src/main/java/seedu/address/logic/commands/SelectCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -package seedu.address.logic.commands; - -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.core.Messages; -import seedu.address.commons.events.ui.JumpToListRequestEvent; -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * Selects a person identified using it's last displayed index from the address book. - */ -public class SelectCommand extends Command { - - public final int targetIndex; - - public static final String COMMAND_WORD = "select"; - - public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Selects the person identified by the index number used in the last person listing.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; - - public static final String MESSAGE_SELECT_PERSON_SUCCESS = "Selected Person: %1$s"; - - public SelectCommand(int targetIndex) { - this.targetIndex = targetIndex; - } - - @Override - public CommandResult execute() { - - UnmodifiableObservableList lastShownList = model.getFilteredPersonList(); - - if (lastShownList.size() < targetIndex) { - indicateAttemptToExecuteIncorrectCommand(); - return new CommandResult(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - EventsCenter.getInstance().post(new JumpToListRequestEvent(targetIndex - 1)); - return new CommandResult(String.format(MESSAGE_SELECT_PERSON_SUCCESS, targetIndex)); - - } - -} diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/address/logic/parser/Parser.java deleted file mode 100644 index 959b2cd0383c..000000000000 --- a/src/main/java/seedu/address/logic/parser/Parser.java +++ /dev/null @@ -1,192 +0,0 @@ -package seedu.address.logic.parser; - -import seedu.address.logic.commands.*; -import seedu.address.commons.util.StringUtil; -import seedu.address.commons.exceptions.IllegalValueException; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; - -/** - * Parses user input. - */ -public class Parser { - - /** - * Used for initial separation of command word and args. - */ - private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); - - private static final Pattern PERSON_INDEX_ARGS_FORMAT = Pattern.compile("(?.+)"); - - private static final Pattern KEYWORDS_ARGS_FORMAT = - Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace - - private static final Pattern PERSON_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes - Pattern.compile("(?[^/]+)" - + " (?p?)p/(?[^/]+)" - + " (?p?)e/(?[^/]+)" - + " (?p?)a/(?
[^/]+)" - + "(?(?: t/[^/]+)*)"); // variable number of tags - - public Parser() {} - - /** - * Parses user input into command for execution. - * - * @param userInput full user input string - * @return the command based on the user input - */ - public Command parseCommand(String userInput) { - final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); - if (!matcher.matches()) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); - } - - final String commandWord = matcher.group("commandWord"); - final String arguments = matcher.group("arguments"); - switch (commandWord) { - - case AddCommand.COMMAND_WORD: - return prepareAdd(arguments); - - case SelectCommand.COMMAND_WORD: - return prepareSelect(arguments); - - case DeleteCommand.COMMAND_WORD: - return prepareDelete(arguments); - - case ClearCommand.COMMAND_WORD: - return new ClearCommand(); - - case FindCommand.COMMAND_WORD: - return prepareFind(arguments); - - case ListCommand.COMMAND_WORD: - return new ListCommand(); - - case ExitCommand.COMMAND_WORD: - return new ExitCommand(); - - case HelpCommand.COMMAND_WORD: - return new HelpCommand(); - - default: - return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); - } - } - - /** - * Parses arguments in the context of the add person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareAdd(String args){ - final Matcher matcher = PERSON_DATA_ARGS_FORMAT.matcher(args.trim()); - // Validate arg string format - if (!matcher.matches()) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); - } - try { - return new AddCommand( - matcher.group("name"), - matcher.group("phone"), - matcher.group("email"), - matcher.group("address"), - getTagsFromArgs(matcher.group("tagArguments")) - ); - } catch (IllegalValueException ive) { - return new IncorrectCommand(ive.getMessage()); - } - } - - /** - * Extracts the new person's tags from the add command's tag arguments string. - * Merges duplicate tag strings. - */ - private static Set getTagsFromArgs(String tagArguments) throws IllegalValueException { - // no tags - if (tagArguments.isEmpty()) { - return Collections.emptySet(); - } - // replace first delimiter prefix, then split - final Collection tagStrings = Arrays.asList(tagArguments.replaceFirst(" t/", "").split(" t/")); - return new HashSet<>(tagStrings); - } - - /** - * Parses arguments in the context of the delete person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareDelete(String args) { - - Optional index = parseIndex(args); - if(!index.isPresent()){ - return new IncorrectCommand( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); - } - - return new DeleteCommand(index.get()); - } - - /** - * Parses arguments in the context of the select person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareSelect(String args) { - Optional index = parseIndex(args); - if(!index.isPresent()){ - return new IncorrectCommand( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE)); - } - - return new SelectCommand(index.get()); - } - - /** - * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index. - * Returns an {@code Optional.empty()} otherwise. - */ - private Optional parseIndex(String command) { - final Matcher matcher = PERSON_INDEX_ARGS_FORMAT.matcher(command.trim()); - if (!matcher.matches()) { - return Optional.empty(); - } - - String index = matcher.group("targetIndex"); - if(!StringUtil.isUnsignedInteger(index)){ - return Optional.empty(); - } - return Optional.of(Integer.parseInt(index)); - - } - - /** - * Parses arguments in the context of the find person command. - * - * @param args full command args string - * @return the prepared command - */ - private Command prepareFind(String args) { - final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); - if (!matcher.matches()) { - return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, - FindCommand.MESSAGE_USAGE)); - } - - // keywords delimited by whitespace - final String[] keywords = matcher.group("keywords").split("\\s+"); - final Set keywordSet = new HashSet<>(Arrays.asList(keywords)); - return new FindCommand(keywordSet); - } - -} \ No newline at end of file diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java deleted file mode 100644 index 298cc1b82ce8..000000000000 --- a/src/main/java/seedu/address/model/AddressBook.java +++ /dev/null @@ -1,163 +0,0 @@ -package seedu.address.model; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * Wraps all data at the address-book level - * Duplicates are not allowed (by .equals comparison) - */ -public class AddressBook implements ReadOnlyAddressBook { - - private final UniquePersonList persons; - private final UniqueTagList tags; - - { - persons = new UniquePersonList(); - tags = new UniqueTagList(); - } - - public AddressBook() {} - - /** - * Persons and Tags are copied into this addressbook - */ - public AddressBook(ReadOnlyAddressBook toBeCopied) { - this(toBeCopied.getUniquePersonList(), toBeCopied.getUniqueTagList()); - } - - /** - * Persons and Tags are copied into this addressbook - */ - public AddressBook(UniquePersonList persons, UniqueTagList tags) { - resetData(persons.getInternalList(), tags.getInternalList()); - } - - public static ReadOnlyAddressBook getEmptyAddressBook() { - return new AddressBook(); - } - -//// list overwrite operations - - public ObservableList getPersons() { - return persons.getInternalList(); - } - - public void setPersons(List persons) { - this.persons.getInternalList().setAll(persons); - } - - public void setTags(Collection tags) { - this.tags.getInternalList().setAll(tags); - } - - public void resetData(Collection newPersons, Collection newTags) { - setPersons(newPersons.stream().map(Person::new).collect(Collectors.toList())); - setTags(newTags); - } - - public void resetData(ReadOnlyAddressBook newData) { - resetData(newData.getPersonList(), newData.getTagList()); - } - -//// person-level operations - - /** - * Adds a person to the address book. - * Also checks the new person's tags and updates {@link #tags} with any new tags found, - * and updates the Tag objects in the person to point to those in {@link #tags}. - * - * @throws UniquePersonList.DuplicatePersonException if an equivalent person already exists. - */ - public void addPerson(Person p) throws UniquePersonList.DuplicatePersonException { - syncTagsWithMasterList(p); - persons.add(p); - } - - /** - * Ensures that every tag in this person: - * - exists in the master list {@link #tags} - * - points to a Tag object in the master list - */ - private void syncTagsWithMasterList(Person person) { - final UniqueTagList personTags = person.getTags(); - tags.mergeFrom(personTags); - - // Create map with values = tag object references in the master list - final Map masterTagObjects = new HashMap<>(); - for (Tag tag : tags) { - masterTagObjects.put(tag, tag); - } - - // Rebuild the list of person tags using references from the master list - final Set commonTagReferences = new HashSet<>(); - for (Tag tag : personTags) { - commonTagReferences.add(masterTagObjects.get(tag)); - } - person.setTags(new UniqueTagList(commonTagReferences)); - } - - public boolean removePerson(ReadOnlyPerson key) throws UniquePersonList.PersonNotFoundException { - if (persons.remove(key)) { - return true; - } else { - throw new UniquePersonList.PersonNotFoundException(); - } - } - -//// tag-level operations - - public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { - tags.add(t); - } - -//// util methods - - @Override - public String toString() { - return persons.getInternalList().size() + " persons, " + tags.getInternalList().size() + " tags"; - // TODO: refine later - } - - @Override - public List getPersonList() { - return Collections.unmodifiableList(persons.getInternalList()); - } - - @Override - public List getTagList() { - return Collections.unmodifiableList(tags.getInternalList()); - } - - @Override - public UniquePersonList getUniquePersonList() { - return this.persons; - } - - @Override - public UniqueTagList getUniqueTagList() { - return this.tags; - } - - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof AddressBook // instanceof handles nulls - && this.persons.equals(((AddressBook) other).persons) - && this.tags.equals(((AddressBook) other).tags)); - } - - @Override - public int hashCode() { - // use this method for custom fields hashing instead of implementing your own - return Objects.hash(persons, tags); - } -} diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java deleted file mode 100644 index d14a27a93b5e..000000000000 --- a/src/main/java/seedu/address/model/Model.java +++ /dev/null @@ -1,35 +0,0 @@ -package seedu.address.model; - -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; - -import java.util.Set; - -/** - * The API of the Model component. - */ -public interface Model { - /** Clears existing backing model and replaces with the provided new data. */ - void resetData(ReadOnlyAddressBook newData); - - /** Returns the AddressBook */ - ReadOnlyAddressBook getAddressBook(); - - /** Deletes the given person. */ - void deletePerson(ReadOnlyPerson target) throws UniquePersonList.PersonNotFoundException; - - /** Adds the given person */ - void addPerson(Person person) throws UniquePersonList.DuplicatePersonException; - - /** Returns the filtered person list as an {@code UnmodifiableObservableList} */ - UnmodifiableObservableList getFilteredPersonList(); - - /** Updates the filter of the filtered person list to show all persons */ - void updateFilteredListToShowAll(); - - /** Updates the filter of the filtered person list to filter by the given keywords*/ - void updateFilteredPersonList(Set keywords); - -} diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java deleted file mode 100644 index 869226d02bf1..000000000000 --- a/src/main/java/seedu/address/model/ModelManager.java +++ /dev/null @@ -1,153 +0,0 @@ -package seedu.address.model; - -import javafx.collections.transformation.FilteredList; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.UnmodifiableObservableList; -import seedu.address.commons.util.StringUtil; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.core.ComponentManager; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; -import seedu.address.model.person.UniquePersonList.PersonNotFoundException; - -import java.util.Set; -import java.util.logging.Logger; - -/** - * Represents the in-memory model of the address book data. - * All changes to any model should be synchronized. - */ -public class ModelManager extends ComponentManager implements Model { - private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - - private final AddressBook addressBook; - private final FilteredList filteredPersons; - - /** - * Initializes a ModelManager with the given AddressBook - * AddressBook and its variables should not be null - */ - public ModelManager(AddressBook src, UserPrefs userPrefs) { - super(); - assert src != null; - assert userPrefs != null; - - logger.fine("Initializing with address book: " + src + " and user prefs " + userPrefs); - - addressBook = new AddressBook(src); - filteredPersons = new FilteredList<>(addressBook.getPersons()); - } - - public ModelManager() { - this(new AddressBook(), new UserPrefs()); - } - - public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { - addressBook = new AddressBook(initialData); - filteredPersons = new FilteredList<>(addressBook.getPersons()); - } - - @Override - public void resetData(ReadOnlyAddressBook newData) { - addressBook.resetData(newData); - indicateAddressBookChanged(); - } - - @Override - public ReadOnlyAddressBook getAddressBook() { - return addressBook; - } - - /** Raises an event to indicate the model has changed */ - private void indicateAddressBookChanged() { - raise(new AddressBookChangedEvent(addressBook)); - } - - @Override - public synchronized void deletePerson(ReadOnlyPerson target) throws PersonNotFoundException { - addressBook.removePerson(target); - indicateAddressBookChanged(); - } - - @Override - public synchronized void addPerson(Person person) throws UniquePersonList.DuplicatePersonException { - addressBook.addPerson(person); - updateFilteredListToShowAll(); - indicateAddressBookChanged(); - } - - //=========== Filtered Person List Accessors =============================================================== - - @Override - public UnmodifiableObservableList getFilteredPersonList() { - return new UnmodifiableObservableList<>(filteredPersons); - } - - @Override - public void updateFilteredListToShowAll() { - filteredPersons.setPredicate(null); - } - - @Override - public void updateFilteredPersonList(Set keywords){ - updateFilteredPersonList(new PredicateExpression(new NameQualifier(keywords))); - } - - private void updateFilteredPersonList(Expression expression) { - filteredPersons.setPredicate(expression::satisfies); - } - - //========== Inner classes/interfaces used for filtering ================================================== - - interface Expression { - boolean satisfies(ReadOnlyPerson person); - String toString(); - } - - private class PredicateExpression implements Expression { - - private final Qualifier qualifier; - - PredicateExpression(Qualifier qualifier) { - this.qualifier = qualifier; - } - - @Override - public boolean satisfies(ReadOnlyPerson person) { - return qualifier.run(person); - } - - @Override - public String toString() { - return qualifier.toString(); - } - } - - interface Qualifier { - boolean run(ReadOnlyPerson person); - String toString(); - } - - private class NameQualifier implements Qualifier { - private Set nameKeyWords; - - NameQualifier(Set nameKeyWords) { - this.nameKeyWords = nameKeyWords; - } - - @Override - public boolean run(ReadOnlyPerson person) { - return nameKeyWords.stream() - .filter(keyword -> StringUtil.containsIgnoreCase(person.getName().fullName, keyword)) - .findAny() - .isPresent(); - } - - @Override - public String toString() { - return "name=" + String.join(", ", nameKeyWords); - } - } - -} diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java deleted file mode 100644 index bfca099b1e81..000000000000 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ /dev/null @@ -1,30 +0,0 @@ -package seedu.address.model; - - -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import java.util.List; - -/** - * Unmodifiable view of an address book - */ -public interface ReadOnlyAddressBook { - - UniqueTagList getUniqueTagList(); - - UniquePersonList getUniquePersonList(); - - /** - * Returns an unmodifiable view of persons list - */ - List getPersonList(); - - /** - * Returns an unmodifiable view of tags list - */ - List getTagList(); - -} diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java deleted file mode 100644 index 5da4d1078236..000000000000 --- a/src/main/java/seedu/address/model/person/Email.java +++ /dev/null @@ -1,56 +0,0 @@ -package seedu.address.model.person; - - -import seedu.address.commons.exceptions.IllegalValueException; - -/** - * Represents a Person's phone number in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)} - */ -public class Email { - - public static final String MESSAGE_EMAIL_CONSTRAINTS = - "Person emails should be 2 alphanumeric/period strings separated by '@'"; - public static final String EMAIL_VALIDATION_REGEX = "[\\w\\.]+@[\\w\\.]+"; - - public final String value; - - /** - * Validates given email. - * - * @throws IllegalValueException if given email address string is invalid. - */ - public Email(String email) throws IllegalValueException { - assert email != null; - email = email.trim(); - if (!isValidEmail(email)) { - throw new IllegalValueException(MESSAGE_EMAIL_CONSTRAINTS); - } - this.value = email; - } - - /** - * Returns if a given string is a valid person email. - */ - public static boolean isValidEmail(String test) { - return test.matches(EMAIL_VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Email // instanceof handles nulls - && this.value.equals(((Email) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java deleted file mode 100644 index 03ffce7d2e79..000000000000 --- a/src/main/java/seedu/address/model/person/Person.java +++ /dev/null @@ -1,90 +0,0 @@ -package seedu.address.model.person; - -import seedu.address.commons.util.CollectionUtil; -import seedu.address.model.tag.UniqueTagList; - -import java.util.Objects; - -/** - * Represents a Person in the address book. - * Guarantees: details are present and not null, field values are validated. - */ -public class Person implements ReadOnlyPerson { - - private Name name; - private Phone phone; - private Email email; - private Address address; - - private UniqueTagList tags; - - /** - * Every field must be present and not null. - */ - public Person(Name name, Phone phone, Email email, Address address, UniqueTagList tags) { - assert !CollectionUtil.isAnyNull(name, phone, email, address, tags); - this.name = name; - this.phone = phone; - this.email = email; - this.address = address; - this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list - } - - /** - * Copy constructor. - */ - public Person(ReadOnlyPerson source) { - this(source.getName(), source.getPhone(), source.getEmail(), source.getAddress(), source.getTags()); - } - - @Override - public Name getName() { - return name; - } - - @Override - public Phone getPhone() { - return phone; - } - - @Override - public Email getEmail() { - return email; - } - - @Override - public Address getAddress() { - return address; - } - - @Override - public UniqueTagList getTags() { - return new UniqueTagList(tags); - } - - /** - * Replaces this person's tags with the tags in the argument tag list. - */ - public void setTags(UniqueTagList replacement) { - tags.setTags(replacement); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof ReadOnlyPerson // instanceof handles nulls - && this.isSameStateAs((ReadOnlyPerson) other)); - } - - @Override - public int hashCode() { - // use this method for custom fields hashing instead of implementing your own - return Objects.hash(name, phone, email, address, tags); - } - - @Override - public String toString() { - return getAsText(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java deleted file mode 100644 index d27b2244b727..000000000000 --- a/src/main/java/seedu/address/model/person/Phone.java +++ /dev/null @@ -1,54 +0,0 @@ -package seedu.address.model.person; - -import seedu.address.commons.exceptions.IllegalValueException; - -/** - * Represents a Person's phone number in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)} - */ -public class Phone { - - public static final String MESSAGE_PHONE_CONSTRAINTS = "Person phone numbers should only contain numbers"; - public static final String PHONE_VALIDATION_REGEX = "\\d+"; - - public final String value; - - /** - * Validates given phone number. - * - * @throws IllegalValueException if given phone string is invalid. - */ - public Phone(String phone) throws IllegalValueException { - assert phone != null; - phone = phone.trim(); - if (!isValidPhone(phone)) { - throw new IllegalValueException(MESSAGE_PHONE_CONSTRAINTS); - } - this.value = phone; - } - - /** - * Returns true if a given string is a valid person phone number. - */ - public static boolean isValidPhone(String test) { - return test.matches(PHONE_VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Phone // instanceof handles nulls - && this.value.equals(((Phone) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java deleted file mode 100644 index 263f1fcc7dd5..000000000000 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ /dev/null @@ -1,98 +0,0 @@ -package seedu.address.model.person; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.commons.exceptions.DuplicateDataException; - -import java.util.*; - -/** - * A list of persons that enforces uniqueness between its elements and does not allow nulls. - * - * Supports a minimal set of list operations. - * - * @see Person#equals(Object) - * @see CollectionUtil#elementsAreUnique(Collection) - */ -public class UniquePersonList implements Iterable { - - /** - * Signals that an operation would have violated the 'no duplicates' property of the list. - */ - public static class DuplicatePersonException extends DuplicateDataException { - protected DuplicatePersonException() { - super("Operation would result in duplicate persons"); - } - } - - /** - * Signals that an operation targeting a specified person in the list would fail because - * there is no such matching person in the list. - */ - public static class PersonNotFoundException extends Exception {} - - private final ObservableList internalList = FXCollections.observableArrayList(); - - /** - * Constructs empty PersonList. - */ - public UniquePersonList() {} - - /** - * Returns true if the list contains an equivalent person as the given argument. - */ - public boolean contains(ReadOnlyPerson toCheck) { - assert toCheck != null; - return internalList.contains(toCheck); - } - - /** - * Adds a person to the list. - * - * @throws DuplicatePersonException if the person to add is a duplicate of an existing person in the list. - */ - public void add(Person toAdd) throws DuplicatePersonException { - assert toAdd != null; - if (contains(toAdd)) { - throw new DuplicatePersonException(); - } - internalList.add(toAdd); - } - - /** - * Removes the equivalent person from the list. - * - * @throws PersonNotFoundException if no such person could be found in the list. - */ - public boolean remove(ReadOnlyPerson toRemove) throws PersonNotFoundException { - assert toRemove != null; - final boolean personFoundAndDeleted = internalList.remove(toRemove); - if (!personFoundAndDeleted) { - throw new PersonNotFoundException(); - } - return personFoundAndDeleted; - } - - public ObservableList getInternalList() { - return internalList; - } - - @Override - public Iterator iterator() { - return internalList.iterator(); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof UniquePersonList // instanceof handles nulls - && this.internalList.equals( - ((UniquePersonList) other).internalList)); - } - - @Override - public int hashCode() { - return internalList.hashCode(); - } -} diff --git a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java b/src/main/java/seedu/address/storage/XmlAdaptedPerson.java deleted file mode 100644 index f2167ec201b4..000000000000 --- a/src/main/java/seedu/address/storage/XmlAdaptedPerson.java +++ /dev/null @@ -1,68 +0,0 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; - -import javax.xml.bind.annotation.XmlElement; -import java.util.ArrayList; -import java.util.List; - -/** - * JAXB-friendly version of the Person. - */ -public class XmlAdaptedPerson { - - @XmlElement(required = true) - private String name; - @XmlElement(required = true) - private String phone; - @XmlElement(required = true) - private String email; - @XmlElement(required = true) - private String address; - - @XmlElement - private List tagged = new ArrayList<>(); - - /** - * No-arg constructor for JAXB use. - */ - public XmlAdaptedPerson() {} - - - /** - * Converts a given Person into this class for JAXB use. - * - * @param source future changes to this will not affect the created XmlAdaptedPerson - */ - public XmlAdaptedPerson(ReadOnlyPerson source) { - name = source.getName().fullName; - phone = source.getPhone().value; - email = source.getEmail().value; - address = source.getAddress().value; - tagged = new ArrayList<>(); - for (Tag tag : source.getTags()) { - tagged.add(new XmlAdaptedTag(tag)); - } - } - - /** - * Converts this jaxb-friendly adapted person object into the model's Person object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted person - */ - public Person toModelType() throws IllegalValueException { - final List personTags = new ArrayList<>(); - for (XmlAdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - final Name name = new Name(this.name); - final Phone phone = new Phone(this.phone); - final Email email = new Email(this.email); - final Address address = new Address(this.address); - final UniqueTagList tags = new UniqueTagList(personTags); - return new Person(name, phone, email, address, tags); - } -} diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java deleted file mode 100644 index 259e9ad0d333..000000000000 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ /dev/null @@ -1,65 +0,0 @@ -package seedu.address.ui; - -import javafx.fxml.FXML; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import seedu.address.model.person.ReadOnlyPerson; - -public class PersonCard extends UiPart{ - - private static final String FXML = "PersonListCard.fxml"; - - @FXML - private HBox cardPane; - @FXML - private Label name; - @FXML - private Label id; - @FXML - private Label phone; - @FXML - private Label address; - @FXML - private Label email; - @FXML - private Label tags; - - private ReadOnlyPerson person; - private int displayedIndex; - - public PersonCard(){ - - } - - public static PersonCard load(ReadOnlyPerson person, int displayedIndex){ - PersonCard card = new PersonCard(); - card.person = person; - card.displayedIndex = displayedIndex; - return UiPartLoader.loadUiPart(card); - } - - @FXML - public void initialize() { - name.setText(person.getName().fullName); - id.setText(displayedIndex + ". "); - phone.setText(person.getPhone().value); - address.setText(person.getAddress().value); - email.setText(person.getEmail().value); - tags.setText(person.tagsString()); - } - - public HBox getLayout() { - return cardPane; - } - - @Override - public void setNode(Node node) { - cardPane = (HBox)node; - } - - @Override - public String getFxmlPath() { - return FXML; - } -} diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java deleted file mode 100644 index 27d9381c47b5..000000000000 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ /dev/null @@ -1,108 +0,0 @@ -package seedu.address.ui; - -import javafx.application.Platform; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.Node; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.SplitPane; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.VBox; -import javafx.stage.Stage; -import seedu.address.commons.events.ui.PersonPanelSelectionChangedEvent; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.commons.core.LogsCenter; - -import java.util.logging.Logger; - -/** - * Panel containing the list of persons. - */ -public class PersonListPanel extends UiPart { - private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); - private static final String FXML = "PersonListPanel.fxml"; - private VBox panel; - private AnchorPane placeHolderPane; - - @FXML - private ListView personListView; - - public PersonListPanel() { - super(); - } - - @Override - public void setNode(Node node) { - panel = (VBox) node; - } - - @Override - public String getFxmlPath() { - return FXML; - } - - @Override - public void setPlaceholder(AnchorPane pane) { - this.placeHolderPane = pane; - } - - public static PersonListPanel load(Stage primaryStage, AnchorPane personListPlaceholder, - ObservableList personList) { - PersonListPanel personListPanel = - UiPartLoader.loadUiPart(primaryStage, personListPlaceholder, new PersonListPanel()); - personListPanel.configure(personList); - return personListPanel; - } - - private void configure(ObservableList personList) { - setConnections(personList); - addToPlaceholder(); - } - - private void setConnections(ObservableList personList) { - personListView.setItems(personList); - personListView.setCellFactory(listView -> new PersonListViewCell()); - setEventHandlerForSelectionChangeEvent(); - } - - private void addToPlaceholder() { - SplitPane.setResizableWithParent(placeHolderPane, false); - placeHolderPane.getChildren().add(panel); - } - - private void setEventHandlerForSelectionChangeEvent() { - personListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null) { - logger.fine("Selection in person list panel changed to : '" + newValue + "'"); - raise(new PersonPanelSelectionChangedEvent(newValue)); - } - }); - } - - public void scrollTo(int index) { - Platform.runLater(() -> { - personListView.scrollTo(index); - personListView.getSelectionModel().clearAndSelect(index); - }); - } - - class PersonListViewCell extends ListCell { - - public PersonListViewCell() { - } - - @Override - protected void updateItem(ReadOnlyPerson person, boolean empty) { - super.updateItem(person, empty); - - if (empty || person == null) { - setGraphic(null); - setText(null); - } else { - setGraphic(PersonCard.load(person, getIndex() + 1).getLayout()); - } - } - } - -} diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/gtd/MainApp.java similarity index 83% rename from src/main/java/seedu/address/MainApp.java rename to src/main/java/seedu/gtd/MainApp.java index 36dc72a74b7a..98d3e7f4c732 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/gtd/MainApp.java @@ -1,26 +1,25 @@ -package seedu.address; +package seedu.gtd; import com.google.common.eventbus.Subscribe; import javafx.application.Application; import javafx.application.Platform; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.core.Version; -import seedu.address.commons.events.ui.ExitAppRequestEvent; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; -import seedu.address.logic.LogicManager; -import seedu.address.model.*; -import seedu.address.commons.util.ConfigUtil; -import seedu.address.storage.Storage; -import seedu.address.storage.StorageManager; -import seedu.address.ui.Ui; -import seedu.address.ui.UiManager; - -import java.io.FileNotFoundException; +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.core.Version; +import seedu.gtd.commons.events.ui.ExitAppRequestEvent; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.ConfigUtil; +import seedu.gtd.commons.util.StringUtil; +import seedu.gtd.logic.Logic; +import seedu.gtd.logic.LogicManager; +import seedu.gtd.model.*; +import seedu.gtd.storage.Storage; +import seedu.gtd.storage.StorageManager; +import seedu.gtd.ui.Ui; +import seedu.gtd.ui.UiManager; + import java.io.IOException; import java.util.Map; import java.util.Optional; @@ -29,6 +28,8 @@ /** * The main entry point to the application. */ + +//@@author addressbook-level4 public class MainApp extends Application { private static final Logger logger = LogsCenter.getLogger(MainApp.class); @@ -45,7 +46,7 @@ public MainApp() {} @Override public void init() throws Exception { - logger.info("=============================[ Initializing AddressBook ]==========================="); + logger.info("=============================[ Initializing TaskList ]==========================="); super.init(); config = initConfig(getApplicationParameter("config")); @@ -75,14 +76,14 @@ private Model initModelManager(Storage storage, UserPrefs userPrefs) { try { addressBookOptional = storage.readAddressBook(); if(!addressBookOptional.isPresent()){ - logger.info("Data file not found. Will be starting with an empty AddressBook"); + logger.info("Data file not found. Will be starting with an empty TaskList"); } initialData = addressBookOptional.orElse(new AddressBook()); } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); + logger.warning("Data file not in the correct format. Will be starting with an empty TaskList"); initialData = new AddressBook(); } catch (IOException e) { - logger.warning("Problem while reading from the file. . Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. . Will be starting with an empty TaskList"); initialData = new AddressBook(); } @@ -139,7 +140,7 @@ protected UserPrefs initPrefs(Config config) { "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. . Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. . Will be starting with an empty TaskList"); initializedPrefs = new UserPrefs(); } @@ -159,13 +160,13 @@ private void initEventsCenter() { @Override public void start(Stage primaryStage) { - logger.info("Starting AddressBook " + MainApp.VERSION); + logger.info("Starting TaskList " + MainApp.VERSION); ui.start(primaryStage); } @Override public void stop() { - logger.info("============================ [ Stopping Address Book ] ============================="); + logger.info("============================ [ Stopping Task List ] ============================="); ui.stop(); try { storage.saveUserPrefs(userPrefs); diff --git a/src/main/java/seedu/address/commons/core/ComponentManager.java b/src/main/java/seedu/gtd/commons/core/ComponentManager.java similarity index 74% rename from src/main/java/seedu/address/commons/core/ComponentManager.java rename to src/main/java/seedu/gtd/commons/core/ComponentManager.java index 4bc8564e5824..1b0561e20d5c 100644 --- a/src/main/java/seedu/address/commons/core/ComponentManager.java +++ b/src/main/java/seedu/gtd/commons/core/ComponentManager.java @@ -1,6 +1,8 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; -import seedu.address.commons.events.BaseEvent; +import java.util.Set; + +import seedu.gtd.commons.events.BaseEvent; /** * Base class for *Manager classes @@ -25,4 +27,9 @@ public ComponentManager(EventsCenter eventsCenter) { protected void raise(BaseEvent event){ eventsCenter.post(event); } + + public void updateFilteredListToShowRemoved() { + // TODO Auto-generated method stub + + } } diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/gtd/commons/core/Config.java similarity index 90% rename from src/main/java/seedu/address/commons/core/Config.java rename to src/main/java/seedu/gtd/commons/core/Config.java index 6441c9ef20f4..173d2ca8a490 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/seedu/gtd/commons/core/Config.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; import java.util.Objects; import java.util.logging.Level; @@ -11,11 +11,11 @@ public class Config { public static final String DEFAULT_CONFIG_FILE = "config.json"; // Config values customizable through config file - private String appTitle = "Address App"; + private String appTitle = "Tary"; private Level logLevel = Level.INFO; private String userPrefsFilePath = "preferences.json"; - private String addressBookFilePath = "data/addressbook.xml"; - private String addressBookName = "MyAddressBook"; + private String addressBookFilePath = "data/tasklist.xml"; + private String addressBookName = "MyTaskList"; public Config() { @@ -92,7 +92,7 @@ public String toString(){ sb.append("\nCurrent log level : " + logLevel); sb.append("\nPreference file Location : " + userPrefsFilePath); sb.append("\nLocal data file location : " + addressBookFilePath); - sb.append("\nAddressBook name : " + addressBookName); + sb.append("\nTask List name : " + addressBookName); return sb.toString(); } diff --git a/src/main/java/seedu/address/commons/core/EventsCenter.java b/src/main/java/seedu/gtd/commons/core/EventsCenter.java similarity index 92% rename from src/main/java/seedu/address/commons/core/EventsCenter.java rename to src/main/java/seedu/gtd/commons/core/EventsCenter.java index 9652cd5c227b..2472fab5018b 100644 --- a/src/main/java/seedu/address/commons/core/EventsCenter.java +++ b/src/main/java/seedu/gtd/commons/core/EventsCenter.java @@ -1,7 +1,8 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; import com.google.common.eventbus.EventBus; -import seedu.address.commons.events.BaseEvent; + +import seedu.gtd.commons.events.BaseEvent; import java.util.logging.Logger; diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/gtd/commons/core/GuiSettings.java similarity index 93% rename from src/main/java/seedu/address/commons/core/GuiSettings.java rename to src/main/java/seedu/gtd/commons/core/GuiSettings.java index e157ac8b8679..60e5c48fb297 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/seedu/gtd/commons/core/GuiSettings.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; import java.awt.*; import java.io.Serializable; @@ -9,8 +9,8 @@ */ public class GuiSettings implements Serializable { - private static final double DEFAULT_HEIGHT = 600; - private static final double DEFAULT_WIDTH = 740; + private static final double DEFAULT_HEIGHT = 768; + private static final double DEFAULT_WIDTH = 1024; private Double windowWidth; private Double windowHeight; diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/gtd/commons/core/LogsCenter.java similarity index 97% rename from src/main/java/seedu/address/commons/core/LogsCenter.java rename to src/main/java/seedu/gtd/commons/core/LogsCenter.java index 17939bab4975..cdd8671c8dd3 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/seedu/gtd/commons/core/LogsCenter.java @@ -1,10 +1,10 @@ -package seedu.address.commons.core; - -import seedu.address.commons.events.BaseEvent; +package seedu.gtd.commons.core; import java.io.IOException; import java.util.logging.*; +import seedu.gtd.commons.events.BaseEvent; + /** * Configures and manages loggers and handlers, including their logging level * Named {@link Logger}s can be obtained from this class
diff --git a/src/main/java/seedu/gtd/commons/core/Messages.java b/src/main/java/seedu/gtd/commons/core/Messages.java new file mode 100644 index 000000000000..cc9ac463d44f --- /dev/null +++ b/src/main/java/seedu/gtd/commons/core/Messages.java @@ -0,0 +1,14 @@ +package seedu.gtd.commons.core; + +/** + * Container for user visible messages. + */ +public class Messages { + + public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; + public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; + public static final String START_END_DATE_INVALID_COMMAND_FORMAT = "Invalid start and end date."; + public static final String MESSAGE_INVALID_TASK_DISPLAYED_INDEX = "The task index provided is invalid"; + public static final String MESSAGE_TASKS_LISTED_OVERVIEW = "%1$d tasks listed!"; + +} diff --git a/src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java b/src/main/java/seedu/gtd/commons/core/UnmodifiableObservableList.java similarity index 99% rename from src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java rename to src/main/java/seedu/gtd/commons/core/UnmodifiableObservableList.java index 5c25d8647a8d..924195a6fc45 100644 --- a/src/main/java/seedu/address/commons/core/UnmodifiableObservableList.java +++ b/src/main/java/seedu/gtd/commons/core/UnmodifiableObservableList.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; import javafx.beans.InvalidationListener; import javafx.collections.ListChangeListener; diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/gtd/commons/core/Version.java similarity index 98% rename from src/main/java/seedu/address/commons/core/Version.java rename to src/main/java/seedu/gtd/commons/core/Version.java index 7ecb85b18f82..90887ef85253 100644 --- a/src/main/java/seedu/address/commons/core/Version.java +++ b/src/main/java/seedu/gtd/commons/core/Version.java @@ -1,4 +1,4 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/seedu/address/commons/events/BaseEvent.java b/src/main/java/seedu/gtd/commons/events/BaseEvent.java similarity index 90% rename from src/main/java/seedu/address/commons/events/BaseEvent.java rename to src/main/java/seedu/gtd/commons/events/BaseEvent.java index 723a9c69fbd5..6b1401131171 100644 --- a/src/main/java/seedu/address/commons/events/BaseEvent.java +++ b/src/main/java/seedu/gtd/commons/events/BaseEvent.java @@ -1,4 +1,4 @@ -package seedu.address.commons.events; +package seedu.gtd.commons.events; public abstract class BaseEvent { diff --git a/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java b/src/main/java/seedu/gtd/commons/events/model/AddressBookChangedEvent.java similarity index 54% rename from src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java rename to src/main/java/seedu/gtd/commons/events/model/AddressBookChangedEvent.java index 347a8359e0d5..70375597e49f 100644 --- a/src/main/java/seedu/address/commons/events/model/AddressBookChangedEvent.java +++ b/src/main/java/seedu/gtd/commons/events/model/AddressBookChangedEvent.java @@ -1,7 +1,7 @@ -package seedu.address.commons.events.model; +package seedu.gtd.commons.events.model; -import seedu.address.commons.events.BaseEvent; -import seedu.address.model.ReadOnlyAddressBook; +import seedu.gtd.commons.events.BaseEvent; +import seedu.gtd.model.ReadOnlyAddressBook; /** Indicates the AddressBook in the model has changed*/ public class AddressBookChangedEvent extends BaseEvent { @@ -14,6 +14,6 @@ public AddressBookChangedEvent(ReadOnlyAddressBook data){ @Override public String toString() { - return "number of persons " + data.getPersonList().size() + ", number of tags " + data.getTagList().size(); + return "number of tasks " + data.getTaskList().size() + ", number of tags " + data.getTagList().size(); } } diff --git a/src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java b/src/main/java/seedu/gtd/commons/events/storage/DataSavingExceptionEvent.java similarity index 78% rename from src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java rename to src/main/java/seedu/gtd/commons/events/storage/DataSavingExceptionEvent.java index f0a0640ee523..1c305683b3cf 100644 --- a/src/main/java/seedu/address/commons/events/storage/DataSavingExceptionEvent.java +++ b/src/main/java/seedu/gtd/commons/events/storage/DataSavingExceptionEvent.java @@ -1,6 +1,6 @@ -package seedu.address.commons.events.storage; +package seedu.gtd.commons.events.storage; -import seedu.address.commons.events.BaseEvent; +import seedu.gtd.commons.events.BaseEvent; /** * Indicates an exception during a file saving diff --git a/src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java b/src/main/java/seedu/gtd/commons/events/ui/ExitAppRequestEvent.java similarity index 70% rename from src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java rename to src/main/java/seedu/gtd/commons/events/ui/ExitAppRequestEvent.java index 9af6194543a3..eaa3a440623d 100644 --- a/src/main/java/seedu/address/commons/events/ui/ExitAppRequestEvent.java +++ b/src/main/java/seedu/gtd/commons/events/ui/ExitAppRequestEvent.java @@ -1,6 +1,6 @@ -package seedu.address.commons.events.ui; +package seedu.gtd.commons.events.ui; -import seedu.address.commons.events.BaseEvent; +import seedu.gtd.commons.events.BaseEvent; /** * Indicates a request for App termination diff --git a/src/main/java/seedu/address/commons/events/ui/IncorrectCommandAttemptedEvent.java b/src/main/java/seedu/gtd/commons/events/ui/IncorrectCommandAttemptedEvent.java similarity index 68% rename from src/main/java/seedu/address/commons/events/ui/IncorrectCommandAttemptedEvent.java rename to src/main/java/seedu/gtd/commons/events/ui/IncorrectCommandAttemptedEvent.java index 991f7ae9fa25..4d34033fd601 100644 --- a/src/main/java/seedu/address/commons/events/ui/IncorrectCommandAttemptedEvent.java +++ b/src/main/java/seedu/gtd/commons/events/ui/IncorrectCommandAttemptedEvent.java @@ -1,7 +1,7 @@ -package seedu.address.commons.events.ui; +package seedu.gtd.commons.events.ui; -import seedu.address.commons.events.BaseEvent; -import seedu.address.logic.commands.Command; +import seedu.gtd.commons.events.BaseEvent; +import seedu.gtd.logic.commands.Command; /** * Indicates an attempt to execute an incorrect command diff --git a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java b/src/main/java/seedu/gtd/commons/events/ui/JumpToListRequestEvent.java similarity index 68% rename from src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java rename to src/main/java/seedu/gtd/commons/events/ui/JumpToListRequestEvent.java index 0580d27aecf5..6d8263cee5bd 100644 --- a/src/main/java/seedu/address/commons/events/ui/JumpToListRequestEvent.java +++ b/src/main/java/seedu/gtd/commons/events/ui/JumpToListRequestEvent.java @@ -1,9 +1,9 @@ -package seedu.address.commons.events.ui; +package seedu.gtd.commons.events.ui; -import seedu.address.commons.events.BaseEvent; +import seedu.gtd.commons.events.BaseEvent; /** - * Indicates a request to jump to the list of persons + * Indicates a request to jump to the list of tasks */ public class JumpToListRequestEvent extends BaseEvent { diff --git a/src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java b/src/main/java/seedu/gtd/commons/events/ui/ShowHelpRequestEvent.java similarity index 70% rename from src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java rename to src/main/java/seedu/gtd/commons/events/ui/ShowHelpRequestEvent.java index a7e40940b2c7..041fcd3f5b81 100644 --- a/src/main/java/seedu/address/commons/events/ui/ShowHelpRequestEvent.java +++ b/src/main/java/seedu/gtd/commons/events/ui/ShowHelpRequestEvent.java @@ -1,6 +1,6 @@ -package seedu.address.commons.events.ui; +package seedu.gtd.commons.events.ui; -import seedu.address.commons.events.BaseEvent; +import seedu.gtd.commons.events.BaseEvent; /** * An event requesting to view the help page. diff --git a/src/main/java/seedu/gtd/commons/events/ui/TaskPanelSelectionChangedEvent.java b/src/main/java/seedu/gtd/commons/events/ui/TaskPanelSelectionChangedEvent.java new file mode 100644 index 000000000000..27b9264f19cd --- /dev/null +++ b/src/main/java/seedu/gtd/commons/events/ui/TaskPanelSelectionChangedEvent.java @@ -0,0 +1,26 @@ +package seedu.gtd.commons.events.ui; + +import seedu.gtd.commons.events.BaseEvent; +import seedu.gtd.model.task.ReadOnlyTask; + +/** + * Represents a selection change in the Task List Panel + */ +public class TaskPanelSelectionChangedEvent extends BaseEvent { + + + private final ReadOnlyTask newSelection; + + public TaskPanelSelectionChangedEvent(ReadOnlyTask newSelection){ + this.newSelection = newSelection; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } + + public ReadOnlyTask getNewSelection() { + return newSelection; + } +} \ No newline at end of file diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/gtd/commons/exceptions/DataConversionException.java similarity index 60% rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java rename to src/main/java/seedu/gtd/commons/exceptions/DataConversionException.java index 1f689bd8e3f9..618900e8919b 100644 --- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java +++ b/src/main/java/seedu/gtd/commons/exceptions/DataConversionException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.gtd.commons.exceptions; /** * Represents an error during conversion of data from one format to another @@ -7,5 +7,9 @@ public class DataConversionException extends Exception { public DataConversionException(Exception cause) { super(cause); } - + + //@@author A0146130W + public DataConversionException(String cause) { + super(cause); + } } diff --git a/src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java b/src/main/java/seedu/gtd/commons/exceptions/DuplicateDataException.java similarity index 85% rename from src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java rename to src/main/java/seedu/gtd/commons/exceptions/DuplicateDataException.java index 17aa63d5020c..be153162172d 100644 --- a/src/main/java/seedu/address/commons/exceptions/DuplicateDataException.java +++ b/src/main/java/seedu/gtd/commons/exceptions/DuplicateDataException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.gtd.commons.exceptions; /** * Signals an error caused by duplicate data where there should be none. diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/gtd/commons/exceptions/IllegalValueException.java similarity index 88% rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java rename to src/main/java/seedu/gtd/commons/exceptions/IllegalValueException.java index a473b43bd86f..299a51519440 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/seedu/gtd/commons/exceptions/IllegalValueException.java @@ -1,4 +1,4 @@ -package seedu.address.commons.exceptions; +package seedu.gtd.commons.exceptions; /** * Signals that some given data does not fulfill some constraints. diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/gtd/commons/util/AppUtil.java similarity index 81% rename from src/main/java/seedu/address/commons/util/AppUtil.java rename to src/main/java/seedu/gtd/commons/util/AppUtil.java index 649cc19aaeda..d8e0aea573d9 100644 --- a/src/main/java/seedu/address/commons/util/AppUtil.java +++ b/src/main/java/seedu/gtd/commons/util/AppUtil.java @@ -1,7 +1,7 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import javafx.scene.image.Image; -import seedu.address.MainApp; +import seedu.gtd.MainApp; /** * A container for App specific utility functions diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/gtd/commons/util/CollectionUtil.java similarity index 96% rename from src/main/java/seedu/address/commons/util/CollectionUtil.java rename to src/main/java/seedu/gtd/commons/util/CollectionUtil.java index fde8394f31e5..0fa06a43a0a5 100644 --- a/src/main/java/seedu/address/commons/util/CollectionUtil.java +++ b/src/main/java/seedu/gtd/commons/util/CollectionUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import java.util.Collection; import java.util.HashSet; diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/gtd/commons/util/ConfigUtil.java similarity index 86% rename from src/main/java/seedu/address/commons/util/ConfigUtil.java rename to src/main/java/seedu/gtd/commons/util/ConfigUtil.java index af42e03df06c..3c9472adf2fa 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/seedu/gtd/commons/util/ConfigUtil.java @@ -1,14 +1,14 @@ -package seedu.address.commons.util; - -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; +package seedu.gtd.commons.util; import java.io.File; import java.io.IOException; import java.util.Optional; import java.util.logging.Logger; +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.exceptions.DataConversionException; + /** * A class for accessing the Config File. */ @@ -55,8 +55,9 @@ public static Optional readConfig(String configFilePath) throws DataConv public static void saveConfig(Config config, String configFilePath) throws IOException { assert config != null; assert configFilePath != null; - + logger.info("Saving config: \n" + config); FileUtil.serializeObjectToJsonFile(new File(configFilePath), config); + logger.info("Config file saved to " + configFilePath); } } diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/gtd/commons/util/FileUtil.java similarity index 98% rename from src/main/java/seedu/address/commons/util/FileUtil.java rename to src/main/java/seedu/gtd/commons/util/FileUtil.java index ca8221250de4..97ce353111a0 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/seedu/gtd/commons/util/FileUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import java.io.File; import java.io.IOException; diff --git a/src/main/java/seedu/address/commons/util/FxViewUtil.java b/src/main/java/seedu/gtd/commons/util/FxViewUtil.java similarity index 92% rename from src/main/java/seedu/address/commons/util/FxViewUtil.java rename to src/main/java/seedu/gtd/commons/util/FxViewUtil.java index 900efa6bf5c3..013b7b2fcb3c 100644 --- a/src/main/java/seedu/address/commons/util/FxViewUtil.java +++ b/src/main/java/seedu/gtd/commons/util/FxViewUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import javafx.scene.Node; import javafx.scene.layout.AnchorPane; diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/gtd/commons/util/JsonUtil.java similarity index 98% rename from src/main/java/seedu/address/commons/util/JsonUtil.java rename to src/main/java/seedu/gtd/commons/util/JsonUtil.java index 80b67de5b7e8..02f872e76492 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/seedu/gtd/commons/util/JsonUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/gtd/commons/util/StringUtil.java similarity index 96% rename from src/main/java/seedu/address/commons/util/StringUtil.java rename to src/main/java/seedu/gtd/commons/util/StringUtil.java index 2e94740456a6..4fbf3b94cdbf 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/gtd/commons/util/StringUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/src/main/java/seedu/address/commons/util/UrlUtil.java b/src/main/java/seedu/gtd/commons/util/UrlUtil.java similarity index 94% rename from src/main/java/seedu/address/commons/util/UrlUtil.java rename to src/main/java/seedu/gtd/commons/util/UrlUtil.java index 6bbab52b9840..7c19154a2372 100644 --- a/src/main/java/seedu/address/commons/util/UrlUtil.java +++ b/src/main/java/seedu/gtd/commons/util/UrlUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import java.net.URL; diff --git a/src/main/java/seedu/address/commons/util/XmlUtil.java b/src/main/java/seedu/gtd/commons/util/XmlUtil.java similarity index 98% rename from src/main/java/seedu/address/commons/util/XmlUtil.java rename to src/main/java/seedu/gtd/commons/util/XmlUtil.java index 2087e7628a1d..afa15a030399 100644 --- a/src/main/java/seedu/address/commons/util/XmlUtil.java +++ b/src/main/java/seedu/gtd/commons/util/XmlUtil.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/gtd/logic/Logic.java similarity index 58% rename from src/main/java/seedu/address/logic/Logic.java rename to src/main/java/seedu/gtd/logic/Logic.java index 4df1bc65cabb..e5efa7d6d694 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/gtd/logic/Logic.java @@ -1,8 +1,8 @@ -package seedu.address.logic; +package seedu.gtd.logic; import javafx.collections.ObservableList; -import seedu.address.logic.commands.CommandResult; -import seedu.address.model.person.ReadOnlyPerson; +import seedu.gtd.logic.commands.CommandResult; +import seedu.gtd.model.task.ReadOnlyTask; /** * API of the Logic component @@ -15,7 +15,7 @@ public interface Logic { */ CommandResult execute(String commandText); - /** Returns the filtered list of persons */ - ObservableList getFilteredPersonList(); + /** Returns the filtered list of tasks */ + ObservableList getFilteredTaskList(); } diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/gtd/logic/LogicManager.java similarity index 57% rename from src/main/java/seedu/address/logic/LogicManager.java rename to src/main/java/seedu/gtd/logic/LogicManager.java index ce4dc1903cff..f6602d7afd4e 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/gtd/logic/LogicManager.java @@ -1,14 +1,14 @@ -package seedu.address.logic; +package seedu.gtd.logic; -import javafx.collections.ObservableList; -import seedu.address.commons.core.ComponentManager; -import seedu.address.commons.core.LogsCenter; -import seedu.address.logic.commands.Command; -import seedu.address.logic.commands.CommandResult; -import seedu.address.logic.parser.Parser; -import seedu.address.model.Model; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.storage.Storage; +import seedu.gtd.commons.core.ComponentManager; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.logic.commands.Command; +import seedu.gtd.logic.commands.CommandResult; +import seedu.gtd.logic.parser.Parser; +import seedu.gtd.model.Model; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.storage.Storage; import java.util.logging.Logger; @@ -35,7 +35,7 @@ public CommandResult execute(String commandText) { } @Override - public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); + public UnmodifiableObservableList getFilteredTaskList() { + return model.getFilteredTaskList(); } } diff --git a/src/main/java/seedu/gtd/logic/commands/AddCommand.java b/src/main/java/seedu/gtd/logic/commands/AddCommand.java new file mode 100644 index 000000000000..3e05f5769132 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/AddCommand.java @@ -0,0 +1,64 @@ +package seedu.gtd.logic.commands; + +import java.util.HashSet; +import java.util.Set; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.task.*; +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; + +/** + * Adds a task to the task list. + */ +//@@author A0130677A +public class AddCommand extends Command { + + public static final String COMMAND_WORD = "add"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a task to the GTD. " + + "Parameters: NAME [s/STARTDATE d/DUEDATE a/ADDRESS p/PRIORITY t/TAGS]...\n" + + "All parameters except name is optional.\n" + + "Example: " + COMMAND_WORD + + " Do CS2103 Tutorial 4 d/noon a/NUS p/3 t/CS2103 tutorial fun"; + + public static final String MESSAGE_SUCCESS = "New task added: %1$s"; + public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task list"; + + private final Task toAdd; + + /** + * Convenience constructor using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public AddCommand(String name, String startDate, String dueDate, String address, String priority, Set tags) + throws IllegalValueException { + final Set tagSet = new HashSet<>(); + for (String tagName : tags) { + tagSet.add(new Tag(tagName)); + } + this.toAdd = new Task( + new Name(name), + new DueDate(startDate), + new DueDate(dueDate), + new Address(address), + new Priority(priority), + new UniqueTagList(tagSet) + ); + } + + //@@author addressbook-level4 + @Override + public CommandResult execute() { + assert model != null; + try { + model.addTask(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } catch (UniqueTaskList.DuplicateTaskException e) { + return new CommandResult(MESSAGE_DUPLICATE_TASK); + } + + } + +} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/gtd/logic/commands/ClearCommand.java similarity index 53% rename from src/main/java/seedu/address/logic/commands/ClearCommand.java rename to src/main/java/seedu/gtd/logic/commands/ClearCommand.java index 522d57189f51..7689aeadc00c 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/seedu/gtd/logic/commands/ClearCommand.java @@ -1,6 +1,6 @@ -package seedu.address.logic.commands; +package seedu.gtd.logic.commands; -import seedu.address.model.AddressBook; +import seedu.gtd.model.AddressBook; /** * Clears the address book. @@ -8,7 +8,8 @@ public class ClearCommand extends Command { public static final String COMMAND_WORD = "clear"; - public static final String MESSAGE_SUCCESS = "Address book has been cleared!"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Clears the Task List."; + public static final String MESSAGE_SUCCESS = "Task List has been cleared!"; public ClearCommand() {} @@ -16,7 +17,7 @@ public ClearCommand() {} @Override public CommandResult execute() { assert model != null; - model.resetData(AddressBook.getEmptyAddressBook()); + model.clearTaskList(); return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/gtd/logic/commands/Command.java similarity index 67% rename from src/main/java/seedu/address/logic/commands/Command.java rename to src/main/java/seedu/gtd/logic/commands/Command.java index 7c0ba2fd0161..187f0883b3c8 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/seedu/gtd/logic/commands/Command.java @@ -1,9 +1,9 @@ -package seedu.address.logic.commands; +package seedu.gtd.logic.commands; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.core.Messages; -import seedu.address.commons.events.ui.IncorrectCommandAttemptedEvent; -import seedu.address.model.Model; +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.core.Messages; +import seedu.gtd.commons.events.ui.IncorrectCommandAttemptedEvent; +import seedu.gtd.model.Model; /** * Represents a command with hidden internal logic and the ability to be executed. @@ -12,13 +12,13 @@ public abstract class Command { protected Model model; /** - * Constructs a feedback message to summarise an operation that displayed a listing of persons. + * Constructs a feedback message to summarise an operation that displayed a listing of tasks. * * @param displaySize used to generate summary - * @return summary message for persons displayed + * @return summary message for tasks displayed */ - public static String getMessageForPersonListShownSummary(int displaySize) { - return String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, displaySize); + public static String getMessageForTaskListShownSummary(int displaySize) { + return String.format(Messages.MESSAGE_TASKS_LISTED_OVERVIEW, displaySize); } /** diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/gtd/logic/commands/CommandResult.java similarity index 87% rename from src/main/java/seedu/address/logic/commands/CommandResult.java rename to src/main/java/seedu/gtd/logic/commands/CommandResult.java index f46f2f31353e..515511706425 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/gtd/logic/commands/CommandResult.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package seedu.gtd.logic.commands; /** * Represents the result of a command execution. diff --git a/src/main/java/seedu/gtd/logic/commands/DeleteCommand.java b/src/main/java/seedu/gtd/logic/commands/DeleteCommand.java new file mode 100644 index 000000000000..4ed6c87e80b4 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/DeleteCommand.java @@ -0,0 +1,50 @@ +package seedu.gtd.logic.commands; + +import seedu.gtd.commons.core.Messages; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; + +/** + * Deletes a task identified using it's last displayed index from the address book. + */ +public class DeleteCommand extends Command { + + public static final String COMMAND_WORD = "delete"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the task identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DELETE_TASK_SUCCESS = "Deleted Task: %1$s"; + + public final int targetIndex; + + public DeleteCommand(int targetIndex) { + this.targetIndex = targetIndex; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask taskToDelete = lastShownList.get(targetIndex - 1); + + try { + model.deleteTask(taskToDelete); + } catch (TaskNotFoundException pnfe) { + assert false : "The target task cannot be missing"; + } + + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); + } + +} diff --git a/src/main/java/seedu/gtd/logic/commands/DoneCommand.java b/src/main/java/seedu/gtd/logic/commands/DoneCommand.java new file mode 100644 index 000000000000..9b0cc1a597b3 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/DoneCommand.java @@ -0,0 +1,72 @@ +package seedu.gtd.logic.commands; + +import seedu.gtd.commons.core.Messages; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; + +/** + * Mark a task as done, identified using it's last displayed index from the address book. + */ + + +//@@author A0130677A +public class DoneCommand extends Command { + + public static final String COMMAND_WORD = "done"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Marks a task as done, by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DONE_TASK_SUCCESS = "Done Task: %1$s"; + + public final int targetIndex; + + public DoneCommand(int targetIndex) { + this.targetIndex = targetIndex; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask toEdit = lastShownList.get(targetIndex-1); + Task taskToUpdate = new Task(toEdit); + + try { + taskToUpdate = updateTask(taskToUpdate, "done", "true"); + } catch (IllegalValueException ive) { + return new CommandResult(ive.getMessage()); + } + + assert model != null; + try { + System.out.println("in donecommand.java"); + System.out.println(taskToUpdate.getName() + " " + taskToUpdate.getisDone()); + System.out.println("index at donecommand:" + targetIndex); + model.doneTask(targetIndex-1, taskToUpdate); + + } catch (TaskNotFoundException e) { + assert false : "The target task cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_DONE_TASK_SUCCESS, taskToUpdate)); + + } + + private Task updateTask(Task taskToUpdate, String detailType, String newDetail) throws IllegalValueException { + taskToUpdate.edit(detailType, newDetail); + return taskToUpdate; + } + +} diff --git a/src/main/java/seedu/gtd/logic/commands/EditCommand.java b/src/main/java/seedu/gtd/logic/commands/EditCommand.java new file mode 100644 index 000000000000..5815bc903698 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/EditCommand.java @@ -0,0 +1,72 @@ +package seedu.gtd.logic.commands; + +import java.util.Hashtable; +import java.util.Set; + +import seedu.gtd.commons.core.Messages; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; + +//@@author A0146130W + /** + * Adds a task to the address book. + */ + public class EditCommand extends Command { + + public static final String COMMAND_WORD = "edit"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ":\n" + + "Edits the task identified by the index number used in the last task listing.\n\t" + + "Parameters: [INDEX] (must be a positive integer) prefix/[NEW DETAIL]\n\t" + + "Example: " + COMMAND_WORD + + " 1 p/3"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Task updated: %1$s"; + + private int targetIndex; + private Hashtable newDetails; + + public EditCommand(int targetIndex, Hashtable newDetails) { + this.targetIndex = targetIndex; + this.newDetails = newDetails; + } + + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + ReadOnlyTask toEdit = lastShownList.get(targetIndex); + Task taskToUpdate = new Task(toEdit); + + assert model != null; + try { + Set detailTypes = newDetails.keySet(); + for(String detailType : detailTypes) { + System.out.println("from edit command: " + detailType + " " + newDetails.get(detailType)); + taskToUpdate = updateTask(taskToUpdate, detailType, newDetails.get(detailType)); + model.editTask(targetIndex, taskToUpdate); + } + } catch (IllegalValueException ive) { + return new CommandResult(ive.getMessage()); + } catch (TaskNotFoundException e) { + assert false : "The target task cannot be missing"; + } + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToUpdate)); + } + + private Task updateTask(Task taskToUpdate, String detailType, String newDetail) throws IllegalValueException { + taskToUpdate.edit(detailType, newDetail); + return taskToUpdate; + } + + } diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/gtd/logic/commands/ExitCommand.java similarity index 62% rename from src/main/java/seedu/address/logic/commands/ExitCommand.java rename to src/main/java/seedu/gtd/logic/commands/ExitCommand.java index d98233ce2a0b..011c9538d821 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/seedu/gtd/logic/commands/ExitCommand.java @@ -1,7 +1,7 @@ -package seedu.address.logic.commands; +package seedu.gtd.logic.commands; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.ui.ExitAppRequestEvent; +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.events.ui.ExitAppRequestEvent; /** * Terminates the program. @@ -9,8 +9,8 @@ public class ExitCommand extends Command { public static final String COMMAND_WORD = "exit"; - - public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ..."; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Exits the program."; + public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Task List as requested ..."; public ExitCommand() {} diff --git a/src/main/java/seedu/gtd/logic/commands/FindCommand.java b/src/main/java/seedu/gtd/logic/commands/FindCommand.java new file mode 100644 index 000000000000..463d17b6f3a4 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/FindCommand.java @@ -0,0 +1,75 @@ +package seedu.gtd.logic.commands; + +import java.util.Set; + +/** + * Finds and lists all tasks in address book whose name contains any of the argument keywords. + * Keyword matching is case sensitive. + */ + +//@@author A0130677A +public class FindCommand extends Command { + public static final String COMMAND_WORD = "find"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose name, date, address, tags and priority contain any of " + + "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n" + + "To search by one particular field type, use t/ for tags, a/ for address, d/ for duedate and p/ for priority.\n" + + "Parameters: [FIELDTYPE] KEYWORD [MORE_KEYWORDS]...\n" + + "Example: " + COMMAND_WORD + " cs2103, " + COMMAND_WORD + " d/today"; + + //@@author A0146130W + private final String keywords; + private Set keywordSet; + private final String cmd; + + public FindCommand(String keywords, Set keywordSet, String cmd) { + this.keywords = keywords; + this.keywordSet = keywordSet; + this.cmd = cmd; + } + + private String getMessageForTaskListShownSummaryIfExactPhraseNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } + + private String getMessageForTaskListShownSummaryIfExactFieldNotFound(int displaySize) { + String task_tasks = (displaySize == 1) ? "task" : "tasks"; + + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found in the specified field type. Listing " + displaySize + " " + task_tasks + " containing the keywords entered instead."; + return String.format(MESSAGE_IF_EXACT_PHRASE_NOT_FOUND); + } + + + //@@author A0130677A + @Override + public CommandResult execute() { + System.out.println("command: " + cmd); + + // search by parameter if specified + if (cmd != "nil") { + model.updateFilteredTaskList(keywords, cmd); + } else { + // search by exact name + model.updateFilteredTaskList(keywords, keywordSet); + } + if (!model.getFilteredTaskList().isEmpty()) { + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } + + // search by keywords + model.updateFilteredTaskList(keywords, "nil"); + + if (!model.getFilteredTaskList().isEmpty()) { + if (cmd == "nil") { + return new CommandResult(getMessageForTaskListShownSummaryIfExactPhraseNotFound(model.getFilteredTaskList().size())); + } else { + return new CommandResult(getMessageForTaskListShownSummaryIfExactFieldNotFound(model.getFilteredTaskList().size())); + } + } + + return new CommandResult(getMessageForTaskListShownSummary(model.getFilteredTaskList().size())); + } +} diff --git a/src/main/java/seedu/gtd/logic/commands/HelpCommand.java b/src/main/java/seedu/gtd/logic/commands/HelpCommand.java new file mode 100644 index 000000000000..628f09c0bf5d --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/HelpCommand.java @@ -0,0 +1,62 @@ +package seedu.gtd.logic.commands; + + +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.events.ui.ShowHelpRequestEvent; + +/** + * Format full help instructions for every command for display. + */ +//@@author A0139158X +public class HelpCommand extends Command { + + public static final String COMMAND_WORD = "help"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" + + "Parameters: COMMANDWORD\n" + + "Example: " + COMMAND_WORD + " add"; + + public static final String SHOWING_HELP_MESSAGE = "Opened help window."; + + public final String argument; + + public HelpCommand(String arg) { + this.argument=arg; + } + + @Override + public CommandResult execute() { + + switch (argument) { + + case AddCommand.COMMAND_WORD: + return new CommandResult(AddCommand.MESSAGE_USAGE); + + case SelectCommand.COMMAND_WORD: + return new CommandResult(SelectCommand.MESSAGE_USAGE); + + case DeleteCommand.COMMAND_WORD: + return new CommandResult(DeleteCommand.MESSAGE_USAGE); + + case ClearCommand.COMMAND_WORD: + return new CommandResult(ClearCommand.MESSAGE_USAGE); + + case FindCommand.COMMAND_WORD: + return new CommandResult(FindCommand.MESSAGE_USAGE); + + case ListCommand.COMMAND_WORD: + return new CommandResult(ListCommand.MESSAGE_USAGE); + + case ExitCommand.COMMAND_WORD: + return new CommandResult(ExitCommand.MESSAGE_USAGE); + + case HelpCommand.COMMAND_WORD: + EventsCenter.getInstance().post(new ShowHelpRequestEvent()); + return new CommandResult(MESSAGE_USAGE+"/n"+SHOWING_HELP_MESSAGE); + + default: + EventsCenter.getInstance().post(new ShowHelpRequestEvent()); + return new CommandResult(MESSAGE_USAGE+"/n"+SHOWING_HELP_MESSAGE); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/IncorrectCommand.java b/src/main/java/seedu/gtd/logic/commands/IncorrectCommand.java similarity index 92% rename from src/main/java/seedu/address/logic/commands/IncorrectCommand.java rename to src/main/java/seedu/gtd/logic/commands/IncorrectCommand.java index 491d9cb9da35..30564f806f76 100644 --- a/src/main/java/seedu/address/logic/commands/IncorrectCommand.java +++ b/src/main/java/seedu/gtd/logic/commands/IncorrectCommand.java @@ -1,4 +1,4 @@ -package seedu.address.logic.commands; +package seedu.gtd.logic.commands; /** diff --git a/src/main/java/seedu/gtd/logic/commands/ListCommand.java b/src/main/java/seedu/gtd/logic/commands/ListCommand.java new file mode 100644 index 000000000000..8e1e36dbedb1 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/ListCommand.java @@ -0,0 +1,34 @@ +package seedu.gtd.logic.commands; + + +/** + * Lists all tasks in the address book to the user. + */ + +//@@author A0130677A + +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 tasks in the task list."; + public static final String MESSAGE_SUCCESS_LIST = "Listed all undone tasks"; + public static final String MESSAGE_SUCCESS_LIST_DONE = "Listed all tasks done"; + private String arg; + + public ListCommand(String arg) { + this.arg = arg; + } + + @Override + public CommandResult execute() { + System.out.println("args:" + arg); + if (arg.equals(" done")) { + System.out.println("in done"); + model.updateFilteredListToShowRemoved(); + return new CommandResult(MESSAGE_SUCCESS_LIST_DONE); + } else { + model.updateFilteredListToShowUndone(); + return new CommandResult(MESSAGE_SUCCESS_LIST); + } + } +} diff --git a/src/main/java/seedu/gtd/logic/commands/SelectCommand.java b/src/main/java/seedu/gtd/logic/commands/SelectCommand.java new file mode 100644 index 000000000000..ce5816086780 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/SelectCommand.java @@ -0,0 +1,44 @@ +package seedu.gtd.logic.commands; + +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.core.Messages; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.commons.events.ui.JumpToListRequestEvent; +import seedu.gtd.model.task.ReadOnlyTask; + +/** + * Selects a task identified using it's last displayed index from the address book. + */ +public class SelectCommand extends Command { + + public final int targetIndex; + + public static final String COMMAND_WORD = "select"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Selects the task identified by the index number used in the last task listing.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_SELECT_TASK_SUCCESS = "Selected Task: %1$s"; + + public SelectCommand(int targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute() { + + UnmodifiableObservableList lastShownList = model.getFilteredTaskList(); + + if (lastShownList.size() < targetIndex) { + indicateAttemptToExecuteIncorrectCommand(); + return new CommandResult(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + EventsCenter.getInstance().post(new JumpToListRequestEvent(targetIndex - 1)); + return new CommandResult(String.format(MESSAGE_SELECT_TASK_SUCCESS, targetIndex)); + + } + +} diff --git a/src/main/java/seedu/gtd/logic/commands/SetFilePathCommand.java b/src/main/java/seedu/gtd/logic/commands/SetFilePathCommand.java new file mode 100644 index 000000000000..a6fa474316c1 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/SetFilePathCommand.java @@ -0,0 +1,46 @@ +package seedu.gtd.logic.commands; + + +import seedu.gtd.commons.exceptions.IllegalValueException; + +//@@author A0139072H + +/** + * Sets the file path of the saved tasklist to a new file + **/ +public class SetFilePathCommand extends Command { + + public static final String COMMAND_WORD = "setPath"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": sets the new file location. " + + "Parameters: nameofnewfile\n" + + "Example: " + COMMAND_WORD + + " internalFolder/name_of_new_file"; + + public static final String MESSAGE_SUCCESS = "New file location set to: %1$s"; + public static final String MESSAGE_INVALID_LOC_TASK = "The file location is invalid!"; + + private final String newFilePath; + + /** + * Convenience constructor using raw values. + * + * @throws IllegalValueException if any of the raw values are invalid + */ + public SetFilePathCommand(String givenString) + throws IllegalValueException { + this.newFilePath = givenString.trim(); + } + + @Override + public CommandResult execute() { + assert model != null; + try{ + model.setFilePathTask(newFilePath); + } catch (Exception e) { + return new CommandResult(MESSAGE_INVALID_LOC_TASK); + } + return new CommandResult(String.format(MESSAGE_SUCCESS, newFilePath)); + } + +} diff --git a/src/main/java/seedu/gtd/logic/commands/UndoCommand.java b/src/main/java/seedu/gtd/logic/commands/UndoCommand.java new file mode 100644 index 000000000000..48cb8fe8b1d6 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/commands/UndoCommand.java @@ -0,0 +1,23 @@ +//@@author A0146130W + +package seedu.gtd.logic.commands; + +/** + * Deletes a task identified using it's last displayed index from the address book. + */ +public class UndoCommand extends Command { + + public static final String COMMAND_WORD = "undo"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Un-does the most recent modification of the task list."; + public static final String MESSAGE_SUCCESS = "Undo change"; + public static final String MESSAGE_UNDO_LIMIT_REACHED = "Undo limit reached!"; + + public UndoCommand() {} + + @Override + public CommandResult execute() { + if(model.undoAddressBookChange()) return new CommandResult(MESSAGE_SUCCESS); + else return new CommandResult(MESSAGE_UNDO_LIMIT_REACHED); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java b/src/main/java/seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java new file mode 100644 index 000000000000..4b54faad057f --- /dev/null +++ b/src/main/java/seedu/gtd/logic/parser/DateNaturalLanguageProcessor.java @@ -0,0 +1,59 @@ +package seedu.gtd.logic.parser; + +import java.text.Format; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import com.joestelmach.natty.*; + +//@@author A0146130W + +/** + * Uses natty API: http://natty.joestelmach.com to parse natural language into dates or string + */ +public class DateNaturalLanguageProcessor implements NaturalLanguageProcessor { + + private static final com.joestelmach.natty.Parser parser = new com.joestelmach.natty.Parser(); + private static final String DATE_FORMAT = "dd/MM/yyyy HH:mm"; + + @Override + public String formatString(String naturalLanguageDate) { + List dateGroups = parser.parse(naturalLanguageDate); + Date parsedDate; + try { + parsedDate = refineDateGroupList(dateGroups); + } catch (NaturalLanguageException e) { + return ""; + } + return formatDateToString(parsedDate); + } + + //@@author A0130677A + public Date getDate(String naturalLanguageDate) { + List dateGroups = parser.parse(naturalLanguageDate); + Date parsedDate; + try { + parsedDate = refineDateGroupList(dateGroups); + return parsedDate; + } catch (NaturalLanguageException e) { + return null; + } + } + + //@@author A0146130W + + /** + * Chooses the first date from a list of dates that Natty has parsed from the natural language string + * @throws NaturalLanguageException + * */ + private Date refineDateGroupList(List groups) throws NaturalLanguageException { + if(groups.size() == 0) throw new NaturalLanguageException(); + return groups.get(0).getDates().get(0); + } + + private String formatDateToString(Date date) { + Format formatter = new SimpleDateFormat(DATE_FORMAT); + return formatter.format(date); + } +} diff --git a/src/main/java/seedu/gtd/logic/parser/NaturalLanguageProcessor.java b/src/main/java/seedu/gtd/logic/parser/NaturalLanguageProcessor.java new file mode 100644 index 000000000000..9df366a53c1e --- /dev/null +++ b/src/main/java/seedu/gtd/logic/parser/NaturalLanguageProcessor.java @@ -0,0 +1,20 @@ +//@@author A0146130W + +package seedu.gtd.logic.parser; + +import java.util.Date; + +import seedu.gtd.commons.exceptions.DataConversionException; + +public interface NaturalLanguageProcessor { + + /** Takes in a string written in natural language and formats it.*/ + String formatString(String s); + Date getDate(String dueDateRaw); + + public static class NaturalLanguageException extends DataConversionException { + protected NaturalLanguageException() { + super("Natural Language Processor was unable to convert input"); + } + } +} \ No newline at end of file diff --git a/src/main/java/seedu/gtd/logic/parser/Parser.java b/src/main/java/seedu/gtd/logic/parser/Parser.java new file mode 100644 index 000000000000..c27d6494fea8 --- /dev/null +++ b/src/main/java/seedu/gtd/logic/parser/Parser.java @@ -0,0 +1,566 @@ +package seedu.gtd.logic.parser; + +import static seedu.gtd.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.gtd.commons.core.Messages.START_END_DATE_INVALID_COMMAND_FORMAT; +import static seedu.gtd.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.util.StringUtil; +import seedu.gtd.logic.commands.*; + +/** + * Parses user input. + */ +public class Parser { + //@@author addressbook-level4 + + /** + * Used for initial separation of command word and args. + */ + private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); + + private static final Pattern TASK_INDEX_ARGS_FORMAT = Pattern.compile("(?.+)"); + + private static final Pattern KEYWORDS_ARGS_FORMAT = + Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace + +// private static final Pattern TASK_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes +// Pattern.compile("(?[^/]+)" +// + " d/(?[^/]+)" +// + " a/(?
[^/]+)" +// + " p/(?[^/]+)" +// + "(?(?: t/[^/]+)*)"); // variable number of tags + + + //@@author A0130677A + + private static final Pattern NAME_TASK_DATA_ARGS_FORMAT = + Pattern.compile("(?[^/]+) (s|t|p|a|d|z)/.*"); + + private static final Pattern PRIORITY_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* p/(?[^/]+) (s|t|a|d|z)/.*"); + + private static final Pattern ADDRESS_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* a/(?
[^/]+) (s|t|p|d|z)/.*"); + + private static final Pattern STARTDATE_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* s/(?[^/]+) (d|t|a|p|z)/.*"); + + private static final Pattern DUEDATE_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* d/(?[^/]+) (s|t|a|p|z)/.*"); + + private static final Pattern TAGS_TASK_DATA_ARGS_FORMAT = + Pattern.compile(".* t/(?[^/]+) (s|d|a|p|z)/.*"); + + //@@author addressbook-level4 + + private static final Pattern EDIT_DATA_ARGS_FORMAT = + Pattern.compile("(?\\S+)" + + " (?\\S+(?:\\s+\\S+)*)"); + + public Parser() {} + + /** + * Parses user input into command for execution. + * + * @param userInput full user input string + * @return the command based on the user input + */ + public Command parseCommand(String userInput) { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + final String arguments = matcher.group("arguments"); + switch (commandWord) { + + case AddCommand.COMMAND_WORD: + return prepareAdd(arguments); + + case EditCommand.COMMAND_WORD: + return prepareEdit(arguments); + + case SelectCommand.COMMAND_WORD: + return prepareSelect(arguments); + + case DeleteCommand.COMMAND_WORD: + return prepareDelete(arguments); + + case DoneCommand.COMMAND_WORD: + return prepareDone(arguments); + + case ClearCommand.COMMAND_WORD: + return new ClearCommand(); + + case FindCommand.COMMAND_WORD: + return prepareFind(arguments); + + case ListCommand.COMMAND_WORD: + return prepareList(arguments); + + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); + + case HelpCommand.COMMAND_WORD: + return prepareHelp(arguments); + + + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + + case SetFilePathCommand.COMMAND_WORD: + return prepareSetFilePath(arguments); + + + default: + return new IncorrectCommand(MESSAGE_UNKNOWN_COMMAND); + } + } + + /** + * Parses arguments in the context of the add task command. + * + * @param args full command args string + * @return the prepared command + */ + + //@@author A0130677A + + private Command prepareAdd(String args){ + String preprocessedArg = appendEnd(args.trim()); + + final Matcher nameMatcher = NAME_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher startDateMatcher = STARTDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArg); + + String nameToAdd = checkEmptyAndAddDefault(nameMatcher, "name", "nil"); + String startDateToAdd = checkEmptyAndAddDefault(startDateMatcher, "startDate", "nil"); + String dueDateToAdd = checkEmptyAndAddDefault(dueDateMatcher, "dueDate", "nil"); + String addressToAdd = checkEmptyAndAddDefault(addressMatcher, "address", "nil"); + String priorityToAdd = checkEmptyAndAddDefault(priorityMatcher, "priority", "1"); + + // format date if due date or start date is specified + + Date dueDateInDateFormat = null; + Date startDateInDateFormat = null; + + if (dueDateMatcher.matches()) { + dueDateInDateFormat = getDateInDateFormat(dueDateToAdd); + dueDateToAdd = parseDueDate(dueDateToAdd); + System.out.println(dueDateInDateFormat); + } + + if (startDateMatcher.matches()) { + startDateInDateFormat = getDateInDateFormat(startDateToAdd); + startDateToAdd = parseDueDate(startDateToAdd); + } + + // check that end date is strictly later than start date + + if (dueDateInDateFormat != null && startDateInDateFormat != null + && dueDateInDateFormat.compareTo(startDateInDateFormat) < 0) { + return new IncorrectCommand(START_END_DATE_INVALID_COMMAND_FORMAT); + } + + Set tagsProcessed = Collections.emptySet(); + + if (tagsMatcher.matches()) { + tagsProcessed = getTagsFromArgs(tagsMatcher.group("tagArguments")); + } + + + // Validate arg string format + if (!nameMatcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + } + + try { + return new AddCommand( + nameToAdd, + startDateToAdd, + dueDateToAdd, + addressToAdd, + priorityToAdd, + tagsProcessed + ); + } catch (IllegalValueException ive) { + return new IncorrectCommand(ive.getMessage()); + } + } + + private String appendEnd(String args) { + return args + " z/"; + } + + private String checkEmptyAndAddDefault(Matcher matcher, String groupName, String defaultValue) { + if (matcher.matches()) { + return matcher.group(groupName); + } else { + return defaultValue; + } + } + + //@@author A0146130W + + private String parseDueDate(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.formatString(dueDateRaw); + } + + //@@author A0130677A + + private Date getDateInDateFormat(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.getDate(dueDateRaw); + } + + // remove time on date parsed to improve search results + private String removeTimeOnDate(String dueDateRaw) { + String[] dateTime = dueDateRaw.split(" "); + return dateTime[0]; + } + + //@@author addressbook-level4 + /** + * Extracts the new task's tags from the add command's tag arguments string. + * Merges duplicate tag strings. + */ + private static Set getTagsFromArgs(String tagArguments) { + // no tags + if (tagArguments.isEmpty()) { + return Collections.emptySet(); + } + + // replace first delimiter prefix, then split + final Collection tagStrings = Arrays.asList(tagArguments.split(" ")); + return new HashSet<>(tagStrings); + } + + //@@author A0146130W + /** + * Parses arguments in the context of the edit task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareEdit(String args) { + + Optional index = parseIndex(args, EDIT_DATA_ARGS_FORMAT); + final Matcher matcher = EDIT_DATA_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE)); + } + + final String[] splitNewDetails = matcher.group("newDetails").split("\\s+"); + ArrayList combinedDetails = combineSameDetails(splitNewDetails); + + Hashtable newDetailsSet = new Hashtable(); + + for (String detail : combinedDetails) { + String detailType = extractDetailType(detail); + String preparedNewDetail = prepareNewDetail(detailType, detail); + System.out.println("before adding to hashtable: " + detailType + " " + preparedNewDetail); + newDetailsSet.put(detailType, preparedNewDetail); + } + + return new EditCommand( + index.get()-1, + newDetailsSet + ); + } + + private ArrayList combineSameDetails(String[] details) { + ArrayList alDetails = new ArrayList(Arrays.asList(details)); + System.out.println(alDetails.toString()); + + String name = new String(); + String address = new String(); + String dueDate = new String(); + String priority = new String(); + + int currentDetailType = 0; + + if(alDetails.size() == 1) { + return alDetails; + } + + for (String detail: alDetails) { + System.out.println("detail: " + detail); + + if(extractDetailType(detail).equals("name")) { + System.out.println("current detail type: " + currentDetailType); + switch(currentDetailType) { + case 1: address = address + " " + detail; break; + case 2: dueDate = dueDate + " " + detail; break; + case 3: priority = priority + " " + detail; break; + default: { + if(name.isEmpty()) name = detail; + else name = name + " " + detail; + break; + } + } + } + else if(extractDetailType(detail).equals("address")) { + System.out.println("detected address " + detail); + address = detail; + currentDetailType = 1; + } + else if(extractDetailType(detail).equals("dueDate")) { + System.out.println("detected dueDate " + detail); + dueDate = detail; + currentDetailType = 2; + } + else if(extractDetailType(detail).equals("priority")) { + System.out.println("detected priority " + detail); + address = detail; + currentDetailType = 3; + } + } + + ArrayList finalCombined = new ArrayList(); + //does not remove the separate words from the list, they will be overwritten by the final combined string + if(!name.isEmpty()) finalCombined.add(name); + System.out.println("from combining name: " + name); + if(!address.isEmpty()) finalCombined.add(address); + System.out.println("from combining address: " + address); + if(!dueDate.isEmpty()) finalCombined.add(dueDate); + if(!priority.isEmpty()) finalCombined.add(priority); + + System.out.println("from combining: " + finalCombined.toString()); + return finalCombined; + } + + private String removeDetailPrefix(String detailWithPrefix) { + return detailWithPrefix.substring(detailWithPrefix.indexOf('/') + 1); + } + + private String prepareNewDetail(String detailType, String detailWithPrefix) { + String detail = removeDetailPrefix(detailWithPrefix); + if(detailType.equals("dueDate")) detail = parseDueDate(detail); + return detail; + } + + //@@author A0146130W-reused + private String extractDetailType(String args) { + String preprocessedArgs = " " + appendEnd(args.trim()); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + + if(addressMatcher.matches()) { + return "address"; + } + else if(dueDateMatcher.matches()) { + return "dueDate"; + } + else if(priorityMatcher.matches()) { + return "priority"; + } + + return "name"; + } + + //@@author addressbook-level4 + /** + * Parses arguments in the context of the delete task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareDelete(String args) { + + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); + } + + return new DeleteCommand(index.get()); + } + + //@@author A0130677A + + private Command prepareDone(String args) { + + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DoneCommand.MESSAGE_USAGE)); + } + + return new DoneCommand(index.get()); + } + + //@@author addressbook-level4 + + /** + * Parses arguments in the context of the select task command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareSelect(String args) { + Optional index = parseIndex(args); + if(!index.isPresent()){ + return new IncorrectCommand( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE)); + } + + return new SelectCommand(index.get()); + } + + /** + * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index. + * Returns an {@code Optional.empty()} otherwise. + */ + private Optional parseIndex(String command) { + final Matcher matcher = TASK_INDEX_ARGS_FORMAT.matcher(command.trim()); + if (!matcher.matches()) { + return Optional.empty(); + } + + String index = matcher.group("targetIndex"); + if(!StringUtil.isUnsignedInteger(index)){ + return Optional.empty(); + } + return Optional.of(Integer.parseInt(index)); + + } + + //@@author A0146130W + private Optional parseIndex(String command, Pattern matcherFormat) { + final Matcher matcher = matcherFormat.matcher(command.trim()); + if (!matcher.matches()) { + return Optional.empty(); + } + + String index = matcher.group("targetIndex"); + if(!StringUtil.isUnsignedInteger(index)){ + return Optional.empty(); + } + return Optional.of(Integer.parseInt(index)); + + } + + //@@author addressbook-level4 + /** + * Parses arguments in the context of the find task command. + * + * @param args full command args string + * @return the prepared command + */ + + //@@author A0130677A + private Command prepareFind(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + String preprocessedArgs = " " + appendEnd(args.trim()); + final Matcher addressMatcher = ADDRESS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher priorityMatcher = PRIORITY_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher startDateMatcher = STARTDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher dueDateMatcher = DUEDATE_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + final Matcher tagsMatcher = TAGS_TASK_DATA_ARGS_FORMAT.matcher(preprocessedArgs); + + Set defaultSet = new HashSet(); + + if (addressMatcher.matches()) { + String addressToBeFound = addressMatcher.group("address"); + return new FindCommand(addressToBeFound, defaultSet,"address"); + } + if (priorityMatcher.matches()) { + String priorityToBeFound = priorityMatcher.group("priority"); + return new FindCommand(priorityToBeFound, defaultSet, "priority"); + } + if (startDateMatcher.matches()) { + String dueDateToBeFound = dueDateMatcher.group("startDate"); + String parsedDueDateToBeFound = removeTimeOnDate(parseDueDate(dueDateToBeFound)); + return new FindCommand(parsedDueDateToBeFound, defaultSet, "startDate"); + } + if (dueDateMatcher.matches()) { + String dueDateToBeFound = dueDateMatcher.group("dueDate"); + String parsedDueDateToBeFound = removeTimeOnDate(parseDueDate(dueDateToBeFound)); + return new FindCommand(parsedDueDateToBeFound, defaultSet, "dueDate"); + } + if (tagsMatcher.matches()) { + String tagsToBeFound = tagsMatcher.group("tagArguments"); + return new FindCommand(tagsToBeFound, defaultSet,"tagArguments"); + } + + // free-form search by keywords + + final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + FindCommand.MESSAGE_USAGE)); + } + + // keywords delimited by whitespace + final String[] splitKeywords = matcher.group("keywords").split("\\s+"); + final Set keywordSet = new HashSet<>(Arrays.asList(splitKeywords)); + + final String keywords = matcher.group("keywords"); + return new FindCommand(keywords, keywordSet, "nil"); + } + + //@@author addressbook-level4 + +private Command prepareList(String args) { + + // check if parameters are specified and pass specified field to FindCommand + + //String preprocessedArgs = " " + appendEnd(args.trim()); + return new ListCommand(args); +} + + /** + * Parses arguments in the context of the help command. + * + * @param args full command args string + * @return the prepared command + */ + //@@author A0139158X + private Command prepareHelp(String args) { + //if no argument + if (args.equals("")) { + args="help"; + } + + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(args.trim()); + if (!matcher.matches()) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + final String commandWord = matcher.group("commandWord"); + return new HelpCommand(commandWord); + } + + //@@author A0139072H + /** + * Parses arguments in the context of the setFilePath command. + * + * @param args full command args string + * @return the prepared command + */ + private Command prepareSetFilePath(String args) { + if(args.equals("")){ + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SetFilePathCommand.MESSAGE_USAGE)); + } + final String filePath = args; + try { + return new SetFilePathCommand(filePath); + } catch (IllegalValueException e) { + return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, SetFilePathCommand.MESSAGE_USAGE)); + } + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/gtd/model/AddressBook.java b/src/main/java/seedu/gtd/model/AddressBook.java new file mode 100644 index 000000000000..95e614c4f05a --- /dev/null +++ b/src/main/java/seedu/gtd/model/AddressBook.java @@ -0,0 +1,224 @@ +package seedu.gtd.model; + +import javafx.collections.ObservableList; + +import seedu.gtd.commons.util.ConfigUtil; +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; +import seedu.gtd.storage.JsonUserPrefsStorage; +import seedu.gtd.storage.StorageManager; +import seedu.gtd.storage.XmlAddressBookStorage; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Wraps all data at the address-book level + * Duplicates are not allowed (by .equals comparison) + */ +public class AddressBook implements ReadOnlyAddressBook { + + //@@author addressbook-level4 + private final UniqueTaskList tasks; + private final UniqueTagList tags; + + { + tasks = new UniqueTaskList(); + tags = new UniqueTagList(); + } + + public AddressBook() {} + + /** + * Tasks and Tags are copied into this addressbook + */ + public AddressBook(ReadOnlyAddressBook toBeCopied) { + this(toBeCopied.getUniqueTaskList(), toBeCopied.getUniqueTagList()); + } + + /** + * Tasks and Tags are copied into this addressbook + */ + public AddressBook(UniqueTaskList tasks, UniqueTagList tags) { + resetData(tasks.getInternalList(), tags.getInternalList()); + } + + public static ReadOnlyAddressBook getEmptyAddressBook() { + return new AddressBook(); + } + +//@@author A0139072H +//// application-wide operations + public void setFilePathTask(String newFilePath) throws IOException{ + Config changedConfig; + String configFilePathUsed; + + System.out.println("SetFilePathTask"); + + //@@author addressbook-level4 + //Reused config saving + configFilePathUsed = Config.DEFAULT_CONFIG_FILE; + try { + Optional configOptional = ConfigUtil.readConfig(configFilePathUsed); + changedConfig = configOptional.orElse(new Config()); + } catch (DataConversionException e) { + changedConfig = new Config(); + } + + changedConfig.setAddressBookFilePath(newFilePath); + System.out.println("Saved to " + newFilePath); + + //@@author A0139072H + //Save the config back to the file + ConfigUtil.saveConfig(changedConfig, configFilePathUsed); + StorageManager newSaveMgr = new StorageManager( + new XmlAddressBookStorage(newFilePath), + new JsonUserPrefsStorage(changedConfig.getUserPrefsFilePath()) + ); + //Save the addressBook to the new location + newSaveMgr.saveAddressBook(this); + }; + +//@@author addressbook-level4 +//// list overwrite operations + + public ObservableList getTasks() { + return tasks.getInternalList(); + } + + public void setTasks(List tasks) { + this.tasks.getInternalList().setAll(tasks); + } + + public void setTags(Collection tags) { + this.tags.getInternalList().setAll(tags); + } + + public void resetData(Collection newTasks, Collection newTags) { + setTasks(newTasks.stream().map(Task::new).collect(Collectors.toList())); + setTags(newTags); + } + + public void resetData(ReadOnlyAddressBook newData) { + resetData(newData.getTaskList(), newData.getTagList()); + } + +//// task-level operations + + /** + * Adds a task to the address book. + * Also checks the new task's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the task to point to those in {@link #tags}. + * + * @throws UniqueTaskList.DuplicateTaskException if an equivalent task already exists. + */ + public void addTask(Task t) throws UniqueTaskList.DuplicateTaskException { + syncTagsWithMasterList(t); + tasks.add(t); + } + + //@@author A0146130W + /** + * Edits a task in the address book. + * Also checks the updated task's tags and updates {@link #tags} with any new tags found, + * and updates the Tag objects in the task to point to those in {@link #tags}. + * + * @throws UniqueTaskList.TaskNotFoundException if the task was not found. + */ + public void editTask(int index, Task t) throws UniqueTaskList.TaskNotFoundException { + syncTagsWithMasterList(t); + tasks.edit(index, t); + } + + //@@author addressbook-level4 + /** + * Ensures that every tag in this task: + * - exists in the master list {@link #tags} + * - points to a Tag object in the master list + */ + private void syncTagsWithMasterList(Task t) { + final UniqueTagList taskTags = t.getTags(); + tags.mergeFrom(taskTags); + + // Create map with values = tag object references in the master list + final Map masterTagObjects = new HashMap<>(); + for (Tag tag : tags) { + masterTagObjects.put(tag, tag); + } + + // Rebuild the list of task tags using references from the master list + final Set commonTagReferences = new HashSet<>(); + for (Tag tag : taskTags) { + commonTagReferences.add(masterTagObjects.get(tag)); + } + t.setTags(new UniqueTagList(commonTagReferences)); + } + + public boolean removeTask(ReadOnlyTask key) throws UniqueTaskList.TaskNotFoundException { + if (tasks.remove(key)) { + return true; + } else { + throw new UniqueTaskList.TaskNotFoundException(); + } + } + + public void doneTask(int index, Task target) throws TaskNotFoundException { + tasks.done(index, target); + } + +//// tag-level operations + + public void addTag(Tag t) throws UniqueTagList.DuplicateTagException { + tags.add(t); + } + +//// util methods + + @Override + public String toString() { + return tasks.getInternalList().size() + " tasks, " + tags.getInternalList().size() + " tags"; + // TODO: refine later + } + + @Override + public List getTaskList() { + return Collections.unmodifiableList(tasks.getInternalList()); + } + + @Override + public List getTagList() { + return Collections.unmodifiableList(tags.getInternalList()); + } + + @Override + public UniqueTaskList getUniqueTaskList() { + return this.tasks; + } + + @Override + public UniqueTagList getUniqueTagList() { + return this.tags; + } + + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddressBook // instanceof handles nulls + && this.tasks.equals(((AddressBook) other).tasks) + && this.tags.equals(((AddressBook) other).tags)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(tasks, tags); + } +} diff --git a/src/main/java/seedu/gtd/model/Model.java b/src/main/java/seedu/gtd/model/Model.java new file mode 100644 index 000000000000..5473dd2b0960 --- /dev/null +++ b/src/main/java/seedu/gtd/model/Model.java @@ -0,0 +1,61 @@ +package seedu.gtd.model; + +import java.io.IOException; +import java.util.Set; + +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList; + +/** + * The API of the Model component. + */ +public interface Model { + /** Returns the AddressBook */ + ReadOnlyAddressBook getAddressBook(); + + /** Deletes the given task. */ + void deleteTask(ReadOnlyTask target) throws UniqueTaskList.TaskNotFoundException; + + /** Marks the given task as done. */ + void doneTask(int targetIndex, Task target) throws UniqueTaskList.TaskNotFoundException; + + /** Adds the given task */ + void addTask(Task task) throws UniqueTaskList.DuplicateTaskException; + + /** Edits the given task */ + void editTask(int targetIndex, Task task) throws UniqueTaskList.TaskNotFoundException; + + /** Modifies the location of the saved tasklist + * @throws IOException */ + void setFilePathTask(String newFilePath) throws IOException; + + /** Returns the filtered task list as an {@code UnmodifiableObservableList} */ + UnmodifiableObservableList getFilteredTaskList(); + + /** Updates the filter of the filtered task list to show all tasks */ + void updateFilteredListToShowAll(); + + /** Updates the filter of the filtered task list to show all tasks */ + void updateFilteredListToShowRemoved(); + + /** Updates the filter of the filtered task list to filter by the given exact phrase + * @param keywordSet */ + void updateFilteredTaskList(String keywords, Set keywordSet); + + /** Updates the filter of the filtered task list to filter by the given keywords*/ + void updateFilteredTaskList(Set keywordSet); + + /** Updates the filter of the filtered task list to filter by the right parameter*/ + void updateFilteredTaskList(String keywords, String cmd); + + /** Un-does a change to the AddressBook + * @return true if undo command was effective or false if undo is not possible, i.e the stack of previous task list states is empty */ + boolean undoAddressBookChange(); + + /** Clears all tasks */ + void clearTaskList(); + + void updateFilteredListToShowUndone(); +} diff --git a/src/main/java/seedu/gtd/model/ModelManager.java b/src/main/java/seedu/gtd/model/ModelManager.java new file mode 100644 index 000000000000..6abf7124a772 --- /dev/null +++ b/src/main/java/seedu/gtd/model/ModelManager.java @@ -0,0 +1,367 @@ +package seedu.gtd.model; + +import java.io.IOException; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Logger; + +import javafx.collections.transformation.FilteredList; +import seedu.gtd.commons.core.ComponentManager; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.core.UnmodifiableObservableList; +import seedu.gtd.commons.events.model.AddressBookChangedEvent; +import seedu.gtd.commons.util.StringUtil; +import seedu.gtd.model.tag.UniqueTagList; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList; +import seedu.gtd.model.task.UniqueTaskList.TaskNotFoundException; + +/** + * Represents the in-memory model of the address book data. + * All changes to any model should be synchronized. + */ +public class ModelManager extends ComponentManager implements Model { + //@@author addressbook-level4 + + private static final Logger logger = LogsCenter.getLogger(ModelManager.class); + + private AddressBook addressBook; + private final FilteredList filteredTasks; + private Stack previousAddressBook; + + /** + * Initializes a ModelManager with the given AddressBook + * AddressBook and its variables should not be null + */ + public ModelManager(AddressBook src, UserPrefs userPrefs) { + super(); + assert src != null; + assert userPrefs != null; + + logger.fine("Initializing with address book: " + src + " and user prefs " + userPrefs); + + addressBook = new AddressBook(src); + filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new Stack(); + previousAddressBook.push(new AddressBook(addressBook)); + } + + public ModelManager() { + this(new AddressBook(), new UserPrefs()); + } + + public ModelManager(ReadOnlyAddressBook initialData, UserPrefs userPrefs) { + addressBook = new AddressBook(initialData); + filteredTasks = new FilteredList<>(addressBook.getTasks()); + previousAddressBook = new Stack(); + previousAddressBook.push(new AddressBook(addressBook)); + } + + private void resetData(ReadOnlyAddressBook newData) { + addressBook.resetData(newData); + indicateAddressBookChanged(); + } + + @Override + public ReadOnlyAddressBook getAddressBook() { + return addressBook; + } + + /** Raises an event to indicate the model has changed */ + private void indicateAddressBookChanged() { + raise(new AddressBookChangedEvent(addressBook)); + } + + private void savePreviousAddressBook() { + previousAddressBook.push(new AddressBook(addressBook)); + } + + @Override + public boolean undoAddressBookChange() { + if(previousAddressBook.isEmpty()) { + return false; + } + else{ + resetData(previousAddressBook.pop()); + return true; + } + } + + @Override + public synchronized void deleteTask(ReadOnlyTask target) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.removeTask(target); + indicateAddressBookChanged(); + } + + //@@author A0130677A + + @Override + public synchronized void doneTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.doneTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + + //@@author addressbook-level4 + + @Override + public synchronized void addTask(Task task) throws UniqueTaskList.DuplicateTaskException { + savePreviousAddressBook(); + addressBook.addTask(task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + + //@@author A0146130W + @Override + public synchronized void editTask(int targetIndex, Task task) throws TaskNotFoundException { + savePreviousAddressBook(); + addressBook.editTask(targetIndex, task); + updateFilteredListToShowAll(); + indicateAddressBookChanged(); + } + + @Override + public void clearTaskList() { + savePreviousAddressBook(); + resetData(AddressBook.getEmptyAddressBook()); + } + + //@@author addressbook-level4 + //=========== Filtered Task List Accessors =============================================================== + + @Override + public UnmodifiableObservableList getFilteredTaskList() { + return new UnmodifiableObservableList<>(filteredTasks); + } + + //@@author A0130677A + + @Override + public void updateFilteredListToShowAll() { + filteredTasks.setPredicate(null); + updateFilteredListToShowAll(new PredicateExpression(new AllQualifiers())); + //updateFilteredListToShowAll(null); + System.out.println("show all"); + } + + private void updateFilteredListToShowAll(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowRemoved() { + updateFilteredListToShowRemoved(new PredicateExpression(new DoneQualifier())); + } + + private void updateFilteredListToShowRemoved(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredListToShowUndone() { + updateFilteredListToShowUndone(new PredicateExpression(new RemoveDoneQualifier())); + } + + private void updateFilteredListToShowUndone(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + @Override + public void updateFilteredTaskList(Set keywordSet) { + updateFilteredTaskList(new PredicateExpression(new NameQualifier(keywordSet))); + } + + @Override + public void updateFilteredTaskList(String keywords, Set keywordSet){ + updateFilteredTaskList(new PredicateExpression(new orderedNameQualifier(keywords, keywordSet))); + } + + @Override + public void updateFilteredTaskList(String keywords, String cmd) { + updateFilteredTaskList(new PredicateExpression(new otherFieldsQualifier(keywords, cmd))); + } + + private void updateFilteredTaskList(Expression expression) { + filteredTasks.setPredicate(expression::satisfies); + } + + //========== Inner classes/interfaces used for filtering ================================================== + + //@@author addressbook-level4 + interface Expression { + boolean satisfies(ReadOnlyTask task); + String toString(); + } + + private class PredicateExpression implements Expression { + + private final Qualifier qualifier; + + PredicateExpression(Qualifier qualifier) { + this.qualifier = qualifier; + } + + @Override + public boolean satisfies(ReadOnlyTask task) { + return qualifier.run(task); + } + + @Override + public String toString() { + return qualifier.toString(); + } + } + + interface Qualifier { + boolean run(ReadOnlyTask task); + String toString(); + } + + private class NameQualifier implements Qualifier { + protected Set keywordSet; + + NameQualifier(Set keywordSet) { + this.keywordSet = keywordSet; + } + + @Override + public boolean run(ReadOnlyTask task) { + return keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); + } + + @Override + public String toString() { + return "name=" + String.join(", ", keywordSet); + } + } + + //@@author A0130677A + + private class otherFieldsQualifier implements Qualifier { + protected String nameKeyWords; + protected String cmd; + + otherFieldsQualifier(String keywords, String cmd) { + this.nameKeyWords = keywords; + this.cmd = cmd; + } + + @Override + public boolean run(ReadOnlyTask task) { + if (cmd == "address") { + System.out.println("finding address.."); + String address = task.getAddress().toString().toLowerCase(); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + return addressMatch; + } else if (cmd == "priority") { + System.out.println("finding priority.."); + String priority = task.getPriority().toString(); + boolean priorityMatch = priority.contains(nameKeyWords); + return priorityMatch; + } else if (cmd == "dueDate") { + System.out.println("finding dueDate.."); + String dueDate = task.getDueDate().toString(); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + return dueDateMatch; + } else if (cmd == "tagArguments") { + System.out.println("finding tags.. "); + UniqueTagList tagsList = task.getTags(); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + return tagsMatch; + } + + // cmd == "nil" + + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + String priority = task.getPriority().toString(); + String address = task.getAddress().toString().toLowerCase(); + String dueDate = task.getDueDate().toString(); + UniqueTagList tagsList = task.getTags(); + + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + boolean addressMatch = address.contains(nameKeyWords.toLowerCase()); + boolean priorityMatch = priority.contains(nameKeyWords); + boolean dueDateMatch = dueDate.contains(nameKeyWords); + boolean tagsMatch = tagsList.containSearch(nameKeyWords.toLowerCase()); + boolean eachWordMatch = false; + + String[] eachWord = nameKeyWords.split(" "); + for (String word : eachWord) { + System.out.println("each: " + word); + eachWordMatch = eachWordMatch || taskFullNameLowerCase.contains(word.toLowerCase()); + } + + return eachWordMatch || nameMatch || addressMatch || priorityMatch || dueDateMatch || tagsMatch; + } + } + + private class orderedNameQualifier extends NameQualifier implements Qualifier { + private String nameKeyWords; + + orderedNameQualifier(String keywords, Set keywordSet) { + super(keywordSet); + this.nameKeyWords = keywords; + } + + @Override + public boolean run(ReadOnlyTask task) { + String taskFullNameLowerCase = task.getName().fullName.toLowerCase(); + boolean nameMatch = taskFullNameLowerCase.contains(nameKeyWords.toLowerCase()); + + boolean eachWordMatch = keywordSet.stream() + .filter(keyword -> StringUtil.containsIgnoreCase(task.getName().fullName, keyword)) + .findAny() + .isPresent(); + return eachWordMatch && nameMatch; + } + } + private class AllQualifiers implements Qualifier { + + AllQualifiers() {} + + @Override + public boolean run(ReadOnlyTask task) { + return true; + } + } + + // to check and return a list of tasks that are already done + private class DoneQualifier implements Qualifier { + + DoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + return task.getisDone(); + } + } + + // default display tasks that are not yet done + private class RemoveDoneQualifier implements Qualifier { + + RemoveDoneQualifier() {} + + @Override + public boolean run(ReadOnlyTask task) { + System.out.println(task.getName()); + return !task.getisDone(); + //return task.getisDone(); + + } + } + @Override + //@@author A0139072H + //application-wide operations + public void setFilePathTask(String newFilePath) throws IOException{ + addressBook.setFilePathTask(newFilePath); + indicateAddressBookChanged(); + //NEEDS TO SAVE TO NEW FILEPATH + }; +} diff --git a/src/main/java/seedu/gtd/model/ReadOnlyAddressBook.java b/src/main/java/seedu/gtd/model/ReadOnlyAddressBook.java new file mode 100644 index 000000000000..59ee8d59eb4b --- /dev/null +++ b/src/main/java/seedu/gtd/model/ReadOnlyAddressBook.java @@ -0,0 +1,30 @@ +package seedu.gtd.model; + + +import java.util.List; + +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.UniqueTaskList; + +/** + * Unmodifiable view of an task list + */ +public interface ReadOnlyAddressBook { + + UniqueTagList getUniqueTagList(); + + UniqueTaskList getUniqueTaskList(); + + /** + * Returns an unmodifiable view of tasks list + */ + List getTaskList(); + + /** + * Returns an unmodifiable view of tags list + */ + List getTagList(); + +} diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/gtd/model/UserPrefs.java similarity index 93% rename from src/main/java/seedu/address/model/UserPrefs.java rename to src/main/java/seedu/gtd/model/UserPrefs.java index da9c8037f495..7fa783926f51 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/seedu/gtd/model/UserPrefs.java @@ -1,9 +1,9 @@ -package seedu.address.model; - -import seedu.address.commons.core.GuiSettings; +package seedu.gtd.model; import java.util.Objects; +import seedu.gtd.commons.core.GuiSettings; + /** * Represents User's preferences. */ diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/gtd/model/tag/Tag.java similarity index 93% rename from src/main/java/seedu/address/model/tag/Tag.java rename to src/main/java/seedu/gtd/model/tag/Tag.java index 5bcffdb5ddf1..93f2c38ecaa2 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/seedu/gtd/model/tag/Tag.java @@ -1,7 +1,7 @@ -package seedu.address.model.tag; +package seedu.gtd.model.tag; -import seedu.address.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.exceptions.IllegalValueException; /** * Represents a Tag in the address book. diff --git a/src/main/java/seedu/address/model/tag/UniqueTagList.java b/src/main/java/seedu/gtd/model/tag/UniqueTagList.java similarity index 85% rename from src/main/java/seedu/address/model/tag/UniqueTagList.java rename to src/main/java/seedu/gtd/model/tag/UniqueTagList.java index 76fb7ff3dc5d..65b207df8226 100644 --- a/src/main/java/seedu/address/model/tag/UniqueTagList.java +++ b/src/main/java/seedu/gtd/model/tag/UniqueTagList.java @@ -1,9 +1,10 @@ -package seedu.address.model.tag; +package seedu.gtd.model.tag; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import seedu.address.commons.util.CollectionUtil; -import seedu.address.commons.exceptions.DuplicateDataException; +import seedu.gtd.commons.exceptions.DuplicateDataException; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.util.CollectionUtil; import java.util.*; @@ -105,6 +106,25 @@ public boolean contains(Tag toCheck) { assert toCheck != null; return internalList.contains(toCheck); } + + + + public boolean containSearch(String toCheck) { + assert toCheck != null; + boolean containsTag = true; + try { + String[] tagsArray = toCheck.split(" "); + + for (String tag : tagsArray) { + System.out.println(tag); + Tag searchTag = new Tag(tag); + containsTag = containsTag && internalList.contains(searchTag); + } + return containsTag; + } catch (IllegalValueException e) { + return false; + } + } /** * Adds a Tag to the list. diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/gtd/model/task/Address.java similarity index 78% rename from src/main/java/seedu/address/model/person/Address.java rename to src/main/java/seedu/gtd/model/task/Address.java index a2bd109c005e..378bda5af211 100644 --- a/src/main/java/seedu/address/model/person/Address.java +++ b/src/main/java/seedu/gtd/model/task/Address.java @@ -1,15 +1,15 @@ -package seedu.address.model.person; +package seedu.gtd.model.task; -import seedu.address.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.exceptions.IllegalValueException; /** - * Represents a Person's address in the address book. + * Represents a Task's address in the address book. * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)} */ public class Address { - public static final String MESSAGE_ADDRESS_CONSTRAINTS = "Person addresses can be in any format"; + public static final String MESSAGE_ADDRESS_CONSTRAINTS = "Task addresses can be in any format"; public static final String ADDRESS_VALIDATION_REGEX = ".+"; public final String value; @@ -28,7 +28,7 @@ public Address(String address) throws IllegalValueException { } /** - * Returns true if a given string is a valid person email. + * Returns true if a given string is a valid task email. */ public static boolean isValidAddress(String test) { return test.matches(ADDRESS_VALIDATION_REGEX); diff --git a/src/main/java/seedu/gtd/model/task/DueDate.java b/src/main/java/seedu/gtd/model/task/DueDate.java new file mode 100644 index 000000000000..f4dc531e345d --- /dev/null +++ b/src/main/java/seedu/gtd/model/task/DueDate.java @@ -0,0 +1,59 @@ +package seedu.gtd.model.task; + +import seedu.gtd.commons.exceptions.IllegalValueException; + +/** + * Represents a Task's due date in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidDueDate(String)} + */ + +public class DueDate { + + public static final String MESSAGE_DUEDATE_CONSTRAINTS = "Task duedate is formatted like the following: Wed Nov 02 15:39:55 UTC 2016 \n" + + " Accepted formal dates: 1978-01-28, 1984/04/02, 1/02/1980, 2/28/79 \n" + + " Relaxed dates: The 31st of April in the year 2008, Fri, 21 Nov 1997, Jan 21, '97, Sun, Nov 21, jan 1st, february twenty-eighth \n" + + " Relative dates: next thursday, last wednesday, today, tomorrow, yesterday, next week, next month, next year, 3 days from now, three weeks ago \n" + + " Prefixes: day after, the day before, the monday after, the monday before, 2 fridays before, 4 tuesdays after \n" + + " Time: 0600h, 06:00 hours, 6pm, 5:30 a.m., 5, 12:59, 23:59, 8p, noon, afternoon, midnight \n" + + " Relative times: 10 seconds ago, in 5 minutes, 4 minutes from now."; + + public final String value; + + /** + * Validates given due date. + * + * @throws IllegalValueException if given due date string is invalid. + */ + public DueDate(String duedate) throws IllegalValueException { + assert duedate != null; + if (isInvalidDueDate(duedate)) { + throw new IllegalValueException(MESSAGE_DUEDATE_CONSTRAINTS); + } + this.value = duedate; + } + + /** + * Returns true if a given string is a valid task due date number. + */ + public static boolean isInvalidDueDate(String test) { + return test.isEmpty(); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DueDate // instanceof handles nulls + && this.value.equals(((DueDate) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/gtd/model/task/Name.java similarity index 78% rename from src/main/java/seedu/address/model/person/Name.java rename to src/main/java/seedu/gtd/model/task/Name.java index 4f30033e70fe..b130242860cc 100644 --- a/src/main/java/seedu/address/model/person/Name.java +++ b/src/main/java/seedu/gtd/model/task/Name.java @@ -1,14 +1,14 @@ -package seedu.address.model.person; +package seedu.gtd.model.task; -import seedu.address.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.exceptions.IllegalValueException; /** - * Represents a Person's name in the address book. + * Represents a task's name in the address book. * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} */ public class Name { - public static final String MESSAGE_NAME_CONSTRAINTS = "Person names should be spaces or alphanumeric characters"; + public static final String MESSAGE_NAME_CONSTRAINTS = "Task names should be spaces or alphanumeric characters"; public static final String NAME_VALIDATION_REGEX = "[\\p{Alnum} ]+"; public final String fullName; @@ -28,7 +28,7 @@ public Name(String name) throws IllegalValueException { } /** - * Returns true if a given string is a valid person name. + * Returns true if a given string is a valid task name. */ public static boolean isValidName(String test) { return test.matches(NAME_VALIDATION_REGEX); diff --git a/src/main/java/seedu/gtd/model/task/Priority.java b/src/main/java/seedu/gtd/model/task/Priority.java new file mode 100644 index 000000000000..25574fa95c72 --- /dev/null +++ b/src/main/java/seedu/gtd/model/task/Priority.java @@ -0,0 +1,59 @@ +package seedu.gtd.model.task; + +import seedu.gtd.commons.exceptions.IllegalValueException; + +/** + * Represents a Task's priority number in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidPriority(String)} + */ +public class Priority { + //@@author A0130677A + public static final String MESSAGE_PRIORITY_CONSTRAINTS = "Task priority number should only contain a number from 1 to 5"; + public static final String PRIORITY_VALIDATION_REGEX = "\\d{1}"; + public static final int MAX_PRIORITY = 5; + public static final int MIN_PRIORITY = 1; + + //@@author + public final String value; + + /** + * Validates given priority number. + * + * @throws IllegalValueException if given priority string is invalid. + */ + public Priority(String priority) throws IllegalValueException { + assert priority != null; + priority = priority.trim(); + if (!isValidPriority(priority)) { + throw new IllegalValueException(MESSAGE_PRIORITY_CONSTRAINTS); + } + this.value = priority; + } + + /** + * Returns true if a given string is a valid task priority number. + */ + //@@author A0130677A + public static boolean isValidPriority(String test) { + return test.matches(PRIORITY_VALIDATION_REGEX) && + Integer.parseInt(test) >= MIN_PRIORITY && Integer.parseInt(test) <= MAX_PRIORITY; + } + //@@author + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Priority // instanceof handles nulls + && this.value.equals(((Priority) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/address/model/person/ReadOnlyPerson.java b/src/main/java/seedu/gtd/model/task/ReadOnlyTask.java similarity index 57% rename from src/main/java/seedu/address/model/person/ReadOnlyPerson.java rename to src/main/java/seedu/gtd/model/task/ReadOnlyTask.java index d45be4b5fe36..8ac7208d8438 100644 --- a/src/main/java/seedu/address/model/person/ReadOnlyPerson.java +++ b/src/main/java/seedu/gtd/model/task/ReadOnlyTask.java @@ -1,55 +1,51 @@ -package seedu.address.model.person; +package seedu.gtd.model.task; -import seedu.address.model.tag.UniqueTagList; +import seedu.gtd.model.tag.UniqueTagList; /** - * A read-only immutable interface for a Person in the addressbook. + * A read-only immutable interface for a Task in the GTD. * Implementations should guarantee: details are present and not null, field values are validated. */ -public interface ReadOnlyPerson { +public interface ReadOnlyTask { Name getName(); - Phone getPhone(); - Email getEmail(); - Address getAddress(); + DueDate getDueDate(); + DueDate getStartDate(); + Address getAddress(); + Priority getPriority(); + boolean getisDone(); /** * The returned TagList is a deep copy of the internal TagList, - * changes on the returned list will not affect the person's internal tags. + * changes on the returned list will not affect the task's internal tags. */ UniqueTagList getTags(); /** * Returns true if both have the same state. (interfaces cannot override .equals) */ - default boolean isSameStateAs(ReadOnlyPerson other) { + default boolean isSameStateAs(ReadOnlyTask other) { return other == this // short circuit if same object || (other != null // this is first to avoid NPE below && other.getName().equals(this.getName()) // state checks here onwards - && other.getPhone().equals(this.getPhone()) - && other.getEmail().equals(this.getEmail()) - && other.getAddress().equals(this.getAddress())); + && other.getDueDate().equals(this.getDueDate())); } /** - * Formats the person as text, showing all contact details. + * Formats the task as text, showing all contact details. */ default String getAsText() { final StringBuilder builder = new StringBuilder(); builder.append(getName()) - .append(" Phone: ") - .append(getPhone()) - .append(" Email: ") - .append(getEmail()) - .append(" Address: ") - .append(getAddress()) + .append(" DueDate: ") + .append(getDueDate()) .append(" Tags: "); getTags().forEach(builder::append); return builder.toString(); } /** - * Returns a string representation of this Person's tags + * Returns a string representation of this Task's tags */ default String tagsString() { final StringBuffer buffer = new StringBuffer(); @@ -61,5 +57,5 @@ default String tagsString() { return buffer.substring(0, buffer.length() - separator.length()); } } - + } diff --git a/src/main/java/seedu/gtd/model/task/Task.java b/src/main/java/seedu/gtd/model/task/Task.java new file mode 100644 index 000000000000..b7410e64c893 --- /dev/null +++ b/src/main/java/seedu/gtd/model/task/Task.java @@ -0,0 +1,153 @@ +package seedu.gtd.model.task; + +import java.util.Objects; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.util.CollectionUtil; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.tag.UniqueTagList; + +/** + * Represents a Task in the task list. + * Guarantees: details are present and not null, field values are validated. + */ +public class Task implements ReadOnlyTask { + + private Name name; + private DueDate dueDate; + private DueDate startDate; + private Address address; + private Priority priority; + private boolean isDone; + + private UniqueTagList tags; + + /** + * Every field must be present and not null. + */ + public Task(Name name, DueDate startDate, DueDate dueDate, Address address, Priority priority, UniqueTagList tags, boolean isDone) { + assert !CollectionUtil.isAnyNull(name, dueDate, address, priority, tags); + this.name = name; + this.startDate = startDate; + this.dueDate = dueDate; + this.address = address; + this.priority = priority; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + this.isDone = isDone; + } + + public Task(Name name, DueDate startDate, DueDate dueDate, Address address, Priority priority, UniqueTagList tags) { + assert !CollectionUtil.isAnyNull(name, dueDate, address, priority, tags); + this.name = name; + this.startDate = startDate; + this.dueDate = dueDate; + this.address = address; + this.priority = priority; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + this.isDone = false; + } + + /** + * Copy constructor. + */ + public Task(ReadOnlyTask source) { + this(source.getName(), source.getStartDate(), source.getDueDate(), source.getAddress(), source.getPriority(), source.getTags(), source.getisDone()); + } + + @Override + public Name getName() { + return name; + } + + @Override + public DueDate getStartDate() { + return startDate; + } + + @Override + public DueDate getDueDate() { + return dueDate; + } + + @Override + public Address getAddress() { + return address; + } + + @Override + public Priority getPriority() { + return priority; + } + + @Override + public boolean getisDone() { + return isDone; + } + + @Override + public UniqueTagList getTags() { + return new UniqueTagList(tags); + } + + public void setName(Name name) { + this.name = name; + } + + public void setStartDate(DueDate startDate) { + this.startDate = startDate; + } + + public void setDueDate(DueDate dueDate) { + this.dueDate = dueDate; + } + + public void setAddress(Address address) { + this.address = address; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } + + public void setisDone(boolean isdone) { + this.isDone = isdone; + } + + public void edit(String detailType, String newDetail) throws IllegalValueException { + + switch(detailType) { + case "startDate": setStartDate(new DueDate(newDetail)); break; + case "dueDate": setDueDate(new DueDate(newDetail)); break; + case "address": setAddress(new Address(newDetail)); break; + case "priority": setPriority(new Priority(newDetail)); break; + case "done": setisDone(true); break; + default: setName(new Name(newDetail)); + } + } + + /** + * Replaces this task's tags with the tags in the argument tag list. + */ + public void setTags(UniqueTagList replacement) { + tags.setTags(replacement); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ReadOnlyTask // instanceof handles nulls + && this.isSameStateAs((ReadOnlyTask) other)); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(name, dueDate, tags); + } + + @Override + public String toString() { + return getAsText(); + } + +} diff --git a/src/main/java/seedu/gtd/model/task/UniqueTaskList.java b/src/main/java/seedu/gtd/model/task/UniqueTaskList.java new file mode 100644 index 000000000000..76645f087dc7 --- /dev/null +++ b/src/main/java/seedu/gtd/model/task/UniqueTaskList.java @@ -0,0 +1,130 @@ +package seedu.gtd.model.task; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.gtd.commons.exceptions.DuplicateDataException; +import seedu.gtd.commons.util.CollectionUtil; + +import java.util.*; + +/** + * A list of tasks that enforces uniqueness between its elements and does not allow nulls. + * + * Supports a minimal set of list operations. + * + * @see Task#equals(Object) + * @see CollectionUtil#elementsAreUnique(Collection) + */ +public class UniqueTaskList implements Iterable { + //@@author addressbook-level4 + /** + * Signals that an operation would have violated the 'no duplicates' property of the list. + */ + public static class DuplicateTaskException extends DuplicateDataException { + protected DuplicateTaskException() { + super("Operation would result in duplicate tasks"); + } + } + + /** + * Signals that an operation targeting a specified task in the list would fail because + * there is no such matching task in the list. + */ + public static class TaskNotFoundException extends Exception {} + + private final ObservableList internalList = FXCollections.observableArrayList(); + + /** + * Constructs empty TaskList. + */ + public UniqueTaskList() {} + + /** + * Returns true if the list contains an equivalent task as the given argument. + */ + public boolean contains(ReadOnlyTask toCheck) { + assert toCheck != null; + return internalList.contains(toCheck); + } + + /** + * Adds a task to the list. + * + * @throws DuplicateTaskException if the task to add is a duplicate of an existing task in the list. + */ + public void add(Task toAdd) throws DuplicateTaskException { + assert toAdd != null; + if (contains(toAdd)) { + throw new DuplicateTaskException(); + } + internalList.add(toAdd); + } + + //@@author A0146130W + /** + * Edits an equivalent task from the list. + * + * @throws TaskNotFoundException if no such task could be found in the list. + */ + public void edit(int targetIndex, Task toEdit) throws TaskNotFoundException { + assert toEdit != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + internalList.set(targetIndex, toEdit); + } + + public void done(int targetIndex, Task taskdone) throws TaskNotFoundException { + System.out.println("in uniquetasklist"); + System.out.println(taskdone.getName() + " " + taskdone.getisDone()); + System.out.println("index at final:" + targetIndex); + assert taskdone != null; + if (invalidIndex(targetIndex)) { + throw new TaskNotFoundException(); + } + System.out.println("marked done in model"); + internalList.set(targetIndex, taskdone); + } + + private boolean invalidIndex(int i) { + if(i < 0 || i >= internalList.size()) return true; + return false; + } + + //@@author addressbook-level4 + /** + * Removes the equivalent task from the list. + * + * @throws TaskNotFoundException if no such task could be found in the list. + */ + public boolean remove(ReadOnlyTask toRemove) throws TaskNotFoundException { + assert toRemove != null; + final boolean taskFoundAndDeleted = internalList.remove(toRemove); + if (!taskFoundAndDeleted) { + throw new TaskNotFoundException(); + } + return taskFoundAndDeleted; + } + + public ObservableList getInternalList() { + return internalList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueTaskList // instanceof handles nulls + && this.internalList.equals( + ((UniqueTaskList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } +} diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/gtd/storage/AddressBookStorage.java similarity index 85% rename from src/main/java/seedu/address/storage/AddressBookStorage.java rename to src/main/java/seedu/gtd/storage/AddressBookStorage.java index 80033086985b..3d163fea96eb 100644 --- a/src/main/java/seedu/address/storage/AddressBookStorage.java +++ b/src/main/java/seedu/gtd/storage/AddressBookStorage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; +package seedu.gtd.storage; import java.io.IOException; import java.util.Optional; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.model.ReadOnlyAddressBook; + /** - * Represents a storage for {@link seedu.address.model.AddressBook}. + * Represents a storage for {@link seedu.gtd.model.AddressBook}. */ public interface AddressBookStorage { diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/gtd/storage/JsonUserPrefsStorage.java similarity index 90% rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java rename to src/main/java/seedu/gtd/storage/JsonUserPrefsStorage.java index 1efa8288e4f6..e6fa52b87297 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/seedu/gtd/storage/JsonUserPrefsStorage.java @@ -1,15 +1,15 @@ -package seedu.address.storage; - -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.UserPrefs; +package seedu.gtd.storage; import java.io.File; import java.io.IOException; import java.util.Optional; import java.util.logging.Logger; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.model.UserPrefs; + /** * A class to access UserPrefs stored in the hard disk as a json file */ diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/gtd/storage/Storage.java similarity index 71% rename from src/main/java/seedu/address/storage/Storage.java rename to src/main/java/seedu/gtd/storage/Storage.java index 91002a8a821a..43a1a5e938b0 100644 --- a/src/main/java/seedu/address/storage/Storage.java +++ b/src/main/java/seedu/gtd/storage/Storage.java @@ -1,15 +1,14 @@ -package seedu.address.storage; +package seedu.gtd.storage; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; - -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Optional; +import seedu.gtd.commons.events.model.AddressBookChangedEvent; +import seedu.gtd.commons.events.storage.DataSavingExceptionEvent; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.UserPrefs; + /** * API of the Storage component */ diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/gtd/storage/StorageManager.java similarity index 85% rename from src/main/java/seedu/address/storage/StorageManager.java rename to src/main/java/seedu/gtd/storage/StorageManager.java index ba1f72f15c27..6fc90a58c64d 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/seedu/gtd/storage/StorageManager.java @@ -1,15 +1,15 @@ -package seedu.address.storage; +package seedu.gtd.storage; import com.google.common.eventbus.Subscribe; -import seedu.address.commons.core.ComponentManager; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; - -import java.io.FileNotFoundException; + +import seedu.gtd.commons.core.ComponentManager; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.events.model.AddressBookChangedEvent; +import seedu.gtd.commons.events.storage.DataSavingExceptionEvent; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.UserPrefs; + import java.io.IOException; import java.util.Optional; import java.util.logging.Logger; diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/gtd/storage/UserPrefsStorage.java similarity index 71% rename from src/main/java/seedu/address/storage/UserPrefsStorage.java rename to src/main/java/seedu/gtd/storage/UserPrefsStorage.java index ad2dc935187c..e9dfa21bc037 100644 --- a/src/main/java/seedu/address/storage/UserPrefsStorage.java +++ b/src/main/java/seedu/gtd/storage/UserPrefsStorage.java @@ -1,13 +1,13 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.UserPrefs; +package seedu.gtd.storage; import java.io.IOException; import java.util.Optional; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.model.UserPrefs; + /** - * Represents a storage for {@link seedu.address.model.UserPrefs}. + * Represents a storage for {@link seedu.gtd.model.UserPrefs}. */ public interface UserPrefsStorage { @@ -20,7 +20,7 @@ public interface UserPrefsStorage { Optional readUserPrefs() throws DataConversionException, IOException; /** - * Saves the given {@link seedu.address.model.UserPrefs} to the storage. + * Saves the given {@link seedu.gtd.model.UserPrefs} to the storage. * @param userPrefs cannot be null. * @throws IOException if there was any problem writing to the file. */ diff --git a/src/main/java/seedu/address/storage/XmlAdaptedTag.java b/src/main/java/seedu/gtd/storage/XmlAdaptedTag.java similarity index 77% rename from src/main/java/seedu/address/storage/XmlAdaptedTag.java rename to src/main/java/seedu/gtd/storage/XmlAdaptedTag.java index b9723fafbc67..54f337601c29 100644 --- a/src/main/java/seedu/address/storage/XmlAdaptedTag.java +++ b/src/main/java/seedu/gtd/storage/XmlAdaptedTag.java @@ -1,11 +1,10 @@ -package seedu.address.storage; - -import seedu.address.commons.util.CollectionUtil; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; +package seedu.gtd.storage; import javax.xml.bind.annotation.XmlValue; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.tag.Tag; + /** * JAXB-friendly adapted version of the Tag. */ @@ -31,7 +30,7 @@ public XmlAdaptedTag(Tag source) { /** * Converts this jaxb-friendly adapted tag object into the model's Tag object. * - * @throws IllegalValueException if there were any data constraints violated in the adapted person + * @throws IllegalValueException if there were any data constraints violated in the adapted task */ public Tag toModelType() throws IllegalValueException { return new Tag(tagName); diff --git a/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java b/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java new file mode 100644 index 000000000000..8015ff34a8e4 --- /dev/null +++ b/src/main/java/seedu/gtd/storage/XmlAdaptedTask.java @@ -0,0 +1,79 @@ +package seedu.gtd.storage; + +import javax.xml.bind.annotation.XmlElement; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.task.*; +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; + +import java.util.ArrayList; +import java.util.List; + +/** + * JAXB-friendly version of the Task. + */ +public class XmlAdaptedTask { + + //@@author A0130677A + @XmlElement(required = true) + private String name; + @XmlElement(required = true) + private String startDate; + @XmlElement(required = true) + private String dueDate; + @XmlElement(required = true) + private String address; + @XmlElement(required = true) + private String priority; + @XmlElement(required = true) + private boolean isDone; + + @XmlElement + private List tagged = new ArrayList<>(); + + /** + * No-arg constructor for JAXB use. + */ + public XmlAdaptedTask() {} + + + /** + * Converts a given Task into this class for JAXB use. + * + * @param source future changes to this will not affect the created XmlAdaptedTask + */ + public XmlAdaptedTask(ReadOnlyTask source) { + name = source.getName().fullName; + startDate = source.getStartDate().value; + dueDate = source.getDueDate().value; + address = source.getAddress().value; + priority = source.getPriority().value; + isDone = source.getisDone(); + tagged = new ArrayList<>(); + for (Tag tag : source.getTags()) { + tagged.add(new XmlAdaptedTag(tag)); + } + } + + /** + * Converts this jaxb-friendly adapted task object into the model's Task object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted task + */ + public Task toModelType() throws IllegalValueException { + final List taskTags = new ArrayList<>(); + for (XmlAdaptedTag tag : tagged) { + taskTags.add(tag.toModelType()); + } + final Name name = new Name(this.name); + final DueDate startDate = new DueDate(this.startDate); + final DueDate dueDate = new DueDate(this.dueDate); + final Address address = new Address(this.address); + final Priority priority = new Priority(this.priority); + final boolean isDone = this.isDone; + System.out.println("printed isdone as: " + isDone); + final UniqueTagList tags = new UniqueTagList(taskTags); + return new Task(name, startDate, dueDate, address, priority, tags, isDone); + } +} diff --git a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java b/src/main/java/seedu/gtd/storage/XmlAddressBookStorage.java similarity index 90% rename from src/main/java/seedu/address/storage/XmlAddressBookStorage.java rename to src/main/java/seedu/gtd/storage/XmlAddressBookStorage.java index 30cb00270cc4..1fce06e1787c 100644 --- a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java +++ b/src/main/java/seedu/gtd/storage/XmlAddressBookStorage.java @@ -1,9 +1,4 @@ -package seedu.address.storage; - -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.ReadOnlyAddressBook; +package seedu.gtd.storage; import java.io.File; import java.io.FileNotFoundException; @@ -11,6 +6,11 @@ import java.util.Optional; import java.util.logging.Logger; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.model.ReadOnlyAddressBook; + /** * A class to access AddressBook data stored as an xml file on the hard disk. */ diff --git a/src/main/java/seedu/address/storage/XmlFileStorage.java b/src/main/java/seedu/gtd/storage/XmlFileStorage.java similarity index 88% rename from src/main/java/seedu/address/storage/XmlFileStorage.java rename to src/main/java/seedu/gtd/storage/XmlFileStorage.java index 27a5210cadaf..cc64fb2aa32d 100644 --- a/src/main/java/seedu/address/storage/XmlFileStorage.java +++ b/src/main/java/seedu/gtd/storage/XmlFileStorage.java @@ -1,9 +1,10 @@ -package seedu.address.storage; - -import seedu.address.commons.util.XmlUtil; -import seedu.address.commons.exceptions.DataConversionException; +package seedu.gtd.storage; import javax.xml.bind.JAXBException; + +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.XmlUtil; + import java.io.File; import java.io.FileNotFoundException; diff --git a/src/main/java/seedu/address/storage/XmlSerializableAddressBook.java b/src/main/java/seedu/gtd/storage/XmlSerializableAddressBook.java similarity index 68% rename from src/main/java/seedu/address/storage/XmlSerializableAddressBook.java rename to src/main/java/seedu/gtd/storage/XmlSerializableAddressBook.java index b7ec533a3a1e..90b9493c8c2b 100644 --- a/src/main/java/seedu/address/storage/XmlSerializableAddressBook.java +++ b/src/main/java/seedu/gtd/storage/XmlSerializableAddressBook.java @@ -1,14 +1,15 @@ -package seedu.address.storage; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.model.person.UniquePersonList; +package seedu.gtd.storage; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.UniqueTaskList; +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -21,12 +22,12 @@ public class XmlSerializableAddressBook implements ReadOnlyAddressBook { @XmlElement - private List persons; + private List tasks; @XmlElement private List tags; { - persons = new ArrayList<>(); + tasks = new ArrayList<>(); tags = new ArrayList<>(); } @@ -39,7 +40,7 @@ public XmlSerializableAddressBook() {} * Conversion */ public XmlSerializableAddressBook(ReadOnlyAddressBook src) { - persons.addAll(src.getPersonList().stream().map(XmlAdaptedPerson::new).collect(Collectors.toList())); + tasks.addAll(src.getTaskList().stream().map(XmlAdaptedTask::new).collect(Collectors.toList())); tags = src.getTagList(); } @@ -55,9 +56,9 @@ public UniqueTagList getUniqueTagList() { } @Override - public UniquePersonList getUniquePersonList() { - UniquePersonList lists = new UniquePersonList(); - for (XmlAdaptedPerson p : persons) { + public UniqueTaskList getUniqueTaskList() { + UniqueTaskList lists = new UniqueTaskList(); + for (XmlAdaptedTask p : tasks) { try { lists.add(p.toModelType()); } catch (IllegalValueException e) { @@ -68,8 +69,8 @@ public UniquePersonList getUniquePersonList() { } @Override - public List getPersonList() { - return persons.stream().map(p -> { + public List getTaskList() { + return tasks.stream().map(p -> { try { return p.toModelType(); } catch (IllegalValueException e) { diff --git a/src/main/java/seedu/address/ui/BrowserPanel.java b/src/main/java/seedu/gtd/ui/BrowserPanel.java similarity index 78% rename from src/main/java/seedu/address/ui/BrowserPanel.java rename to src/main/java/seedu/gtd/ui/BrowserPanel.java index 54b88318019b..51e76d7e1a0a 100644 --- a/src/main/java/seedu/address/ui/BrowserPanel.java +++ b/src/main/java/seedu/gtd/ui/BrowserPanel.java @@ -1,12 +1,12 @@ -package seedu.address.ui; +package seedu.gtd.ui; import javafx.event.Event; import javafx.scene.Node; import javafx.scene.layout.AnchorPane; import javafx.scene.web.WebView; -import seedu.address.commons.util.FxViewUtil; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.commons.core.LogsCenter; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.util.FxViewUtil; +import seedu.gtd.model.task.ReadOnlyTask; import java.util.logging.Logger; @@ -50,14 +50,20 @@ public static BrowserPanel load(AnchorPane placeholder){ return browserPanel; } - public void loadPersonPage(ReadOnlyPerson person) { - loadPage("https://www.google.com.sg/#safe=off&q=" + person.getName().fullName.replaceAll(" ", "+")); + public void loadTaskPage(ReadOnlyTask task) { + loadPage("https://www.google.com.sg/maps/place/" + task.getAddress().value.replaceAll(" ", "+")); } public void loadPage(String url){ browser.getEngine().load(url); } + //@@author A0139072H + public void loadPage(){ + browser.getEngine().load("http://calendar.google.com"); + } + + //@@author addressbook-level4 /** * Frees resources allocated to the browser. */ diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/gtd/ui/CommandBox.java similarity index 92% rename from src/main/java/seedu/address/ui/CommandBox.java rename to src/main/java/seedu/gtd/ui/CommandBox.java index 2e1409a3016c..bf084eaf5fdb 100644 --- a/src/main/java/seedu/address/ui/CommandBox.java +++ b/src/main/java/seedu/gtd/ui/CommandBox.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.gtd.ui; import com.google.common.eventbus.Subscribe; import javafx.fxml.FXML; @@ -7,11 +7,11 @@ import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import seedu.address.commons.events.ui.IncorrectCommandAttemptedEvent; -import seedu.address.logic.Logic; -import seedu.address.logic.commands.*; -import seedu.address.commons.util.FxViewUtil; -import seedu.address.commons.core.LogsCenter; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.events.ui.IncorrectCommandAttemptedEvent; +import seedu.gtd.commons.util.FxViewUtil; +import seedu.gtd.logic.Logic; +import seedu.gtd.logic.commands.*; import java.util.logging.Logger; diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/gtd/ui/HelpWindow.java similarity index 93% rename from src/main/java/seedu/address/ui/HelpWindow.java rename to src/main/java/seedu/gtd/ui/HelpWindow.java index 45b765ab6a0c..6409bbc86f9a 100644 --- a/src/main/java/seedu/address/ui/HelpWindow.java +++ b/src/main/java/seedu/gtd/ui/HelpWindow.java @@ -1,12 +1,12 @@ -package seedu.address.ui; +package seedu.gtd.ui; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.scene.web.WebView; import javafx.stage.Stage; -import seedu.address.commons.util.FxViewUtil; -import seedu.address.commons.core.LogsCenter; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.util.FxViewUtil; import java.util.logging.Logger; diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/gtd/ui/MainWindow.java similarity index 76% rename from src/main/java/seedu/address/ui/MainWindow.java rename to src/main/java/seedu/gtd/ui/MainWindow.java index 2c76aced3b04..45c410110468 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/gtd/ui/MainWindow.java @@ -1,4 +1,7 @@ -package seedu.address.ui; +package seedu.gtd.ui; + +import java.io.File; +import java.net.MalformedURLException; import javafx.fxml.FXML; import javafx.scene.Node; @@ -8,12 +11,12 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.GuiSettings; -import seedu.address.commons.events.ui.ExitAppRequestEvent; -import seedu.address.logic.Logic; -import seedu.address.model.UserPrefs; -import seedu.address.model.person.ReadOnlyPerson; +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.core.GuiSettings; +import seedu.gtd.commons.events.ui.ExitAppRequestEvent; +import seedu.gtd.logic.Logic; +import seedu.gtd.model.UserPrefs; +import seedu.gtd.model.task.ReadOnlyTask; /** * The Main Window. Provides the basic application layout containing @@ -21,16 +24,19 @@ */ public class MainWindow extends UiPart { - private static final String ICON = "/images/address_book_32.png"; + // @@author A0139072H + private static final String ICON = "/images/tary.png"; + + //@@author addressbook-level4 private static final String FXML = "MainWindow.fxml"; - public static final int MIN_HEIGHT = 600; - public static final int MIN_WIDTH = 450; + public static final int MIN_HEIGHT = 768; + public static final int MIN_WIDTH = 1024; private Logic logic; // Independent Ui parts residing in this Ui container private BrowserPanel browserPanel; - private PersonListPanel personListPanel; + private TaskListPanel taskListPanel; private ResultDisplay resultDisplay; private StatusBarFooter statusBarFooter; private CommandBox commandBox; @@ -53,7 +59,7 @@ public class MainWindow extends UiPart { private MenuItem helpMenuItem; @FXML - private AnchorPane personListPanelPlaceholder; + private AnchorPane taskListPanelPlaceholder; @FXML private AnchorPane resultDisplayPlaceholder; @@ -108,14 +114,19 @@ private void setAccelerators() { } void fillInnerParts() { - browserPanel = BrowserPanel.load(browserPlaceholder); - personListPanel = PersonListPanel.load(primaryStage, getPersonListPlaceholder(), logic.getFilteredPersonList()); + browserPanel = BrowserPanel.load(getBrowserPlaceholder()); + browserPanel.loadPage("https://calendar.google.com"); + taskListPanel = TaskListPanel.load(primaryStage, getTaskListPlaceholder(), logic.getFilteredTaskList()); resultDisplay = ResultDisplay.load(primaryStage, getResultDisplayPlaceholder()); statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getAddressBookFilePath()); commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic); } - private AnchorPane getCommandBoxPlaceholder() { + private AnchorPane getBrowserPlaceholder() { + return browserPlaceholder; + } + + private AnchorPane getCommandBoxPlaceholder() { return commandBoxPlaceholder; } @@ -127,8 +138,8 @@ private AnchorPane getResultDisplayPlaceholder() { return resultDisplayPlaceholder; } - public AnchorPane getPersonListPlaceholder() { - return personListPanelPlaceholder; + public AnchorPane getTaskListPlaceholder() { + return taskListPanelPlaceholder; } public void hide() { @@ -182,15 +193,25 @@ private void handleExit() { raise(new ExitAppRequestEvent()); } - public PersonListPanel getPersonListPanel() { - return this.personListPanel; + //@@author A0139072H + /** + * Launches the calendar. + */ + @FXML + private void handleCal() { + browserPanel.loadPage(); + } + + //@@author addressbook-level4 + public TaskListPanel getTaskListPanel() { + return this.taskListPanel; } - public void loadPersonPage(ReadOnlyPerson person) { - browserPanel.loadPersonPage(person); + public void loadTaskPage(ReadOnlyTask task) { + browserPanel.loadTaskPage(task); } public void releaseResources() { browserPanel.freeResources(); } -} +} \ No newline at end of file diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/seedu/gtd/ui/ResultDisplay.java similarity index 96% rename from src/main/java/seedu/address/ui/ResultDisplay.java rename to src/main/java/seedu/gtd/ui/ResultDisplay.java index 37284ee6c696..c8c2e361f4c0 100644 --- a/src/main/java/seedu/address/ui/ResultDisplay.java +++ b/src/main/java/seedu/gtd/ui/ResultDisplay.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.gtd.ui; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -6,7 +6,7 @@ import javafx.scene.control.TextArea; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import seedu.address.commons.util.FxViewUtil; +import seedu.gtd.commons.util.FxViewUtil; /** * A ui for the status bar that is displayed at the header of the application. diff --git a/src/main/java/seedu/address/ui/StatusBarFooter.java b/src/main/java/seedu/gtd/ui/StatusBarFooter.java similarity index 93% rename from src/main/java/seedu/address/ui/StatusBarFooter.java rename to src/main/java/seedu/gtd/ui/StatusBarFooter.java index f74f66be6fc9..fa5c8f28d82e 100644 --- a/src/main/java/seedu/address/ui/StatusBarFooter.java +++ b/src/main/java/seedu/gtd/ui/StatusBarFooter.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.gtd.ui; import com.google.common.eventbus.Subscribe; import javafx.fxml.FXML; @@ -6,10 +6,11 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import javafx.stage.Stage; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.events.model.AddressBookChangedEvent; +import seedu.gtd.commons.util.FxViewUtil; + import org.controlsfx.control.StatusBar; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.util.FxViewUtil; import java.util.Date; import java.util.logging.Logger; diff --git a/src/main/java/seedu/gtd/ui/TaskCard.java b/src/main/java/seedu/gtd/ui/TaskCard.java new file mode 100644 index 000000000000..4377ec19de33 --- /dev/null +++ b/src/main/java/seedu/gtd/ui/TaskCard.java @@ -0,0 +1,75 @@ +package seedu.gtd.ui; + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import seedu.gtd.model.task.ReadOnlyTask; + +public class TaskCard extends UiPart{ + + private static final String FXML = "TaskListCard.fxml"; + + @FXML + private HBox cardPane; + @FXML + private Label name; + @FXML + private Label id; + @FXML + private Label isDone; + @FXML + private Label startDate; + @FXML + private Label dueDate; + @FXML + private Label address; + @FXML + private Label priority; + @FXML + private Label tags; + + private ReadOnlyTask task; + private int displayedIndex; + + public TaskCard(){ + + } + + public static TaskCard load(ReadOnlyTask task, int displayedIndex){ + TaskCard card = new TaskCard(); + card.task = task; + card.displayedIndex = displayedIndex; + return UiPartLoader.loadUiPart(card); + } + + @FXML + public void initialize() { + name.setText(task.getName().fullName); + id.setText(displayedIndex + ". "); + if (task.getisDone()) { + isDone.setText(" [O]"); + } else { + isDone.setText(" [X]"); + } + startDate.setText(task.getStartDate().value); + dueDate.setText(task.getDueDate().value); + address.setText(task.getAddress().value); + priority.setText(task.getPriority().value); + tags.setText(task.tagsString()); + } + + public HBox getLayout() { + return cardPane; + } + + @Override + public void setNode(Node node) { + cardPane = (HBox)node; + } + + @Override + public String getFxmlPath() { + return FXML; + } +} \ No newline at end of file diff --git a/src/main/java/seedu/gtd/ui/TaskListPanel.java b/src/main/java/seedu/gtd/ui/TaskListPanel.java new file mode 100644 index 000000000000..6dfcf21136c0 --- /dev/null +++ b/src/main/java/seedu/gtd/ui/TaskListPanel.java @@ -0,0 +1,107 @@ +package seedu.gtd.ui; + +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.events.ui.TaskPanelSelectionChangedEvent; +import seedu.gtd.model.task.ReadOnlyTask; + +import java.util.logging.Logger; + +/** + * Panel containing the list of tasks. + */ +public class TaskListPanel extends UiPart { + private final Logger logger = LogsCenter.getLogger(TaskListPanel.class); + private static final String FXML = "TaskListPanel.fxml"; + private VBox panel; + private AnchorPane placeHolderPane; + + @FXML + private ListView taskListView; + + public TaskListPanel() { + super(); + } + + @Override + public void setNode(Node node) { + panel = (VBox) node; + } + + @Override + public String getFxmlPath() { + return FXML; + } + + @Override + public void setPlaceholder(AnchorPane pane) { + this.placeHolderPane = pane; + } + + public static TaskListPanel load(Stage primaryStage, AnchorPane taskListPlaceholder, + ObservableList taskList) { + TaskListPanel taskListPanel = + UiPartLoader.loadUiPart(primaryStage, taskListPlaceholder, new TaskListPanel()); + taskListPanel.configure(taskList); + return taskListPanel; + } + + private void configure(ObservableList taskList) { + setConnections(taskList); + addToPlaceholder(); + } + + private void setConnections(ObservableList taskList) { + taskListView.setItems(taskList); + taskListView.setCellFactory(listView -> new TaskListViewCell()); + setEventHandlerForSelectionChangeEvent(); + } + + private void addToPlaceholder() { + SplitPane.setResizableWithParent(placeHolderPane, false); + placeHolderPane.getChildren().add(panel); + } + + private void setEventHandlerForSelectionChangeEvent() { + taskListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + logger.fine("Selection in task list panel changed to : '" + newValue + "'"); + raise(new TaskPanelSelectionChangedEvent(newValue)); + } + }); + } + + public void scrollTo(int index) { + Platform.runLater(() -> { + taskListView.scrollTo(index); + taskListView.getSelectionModel().clearAndSelect(index); + }); + } + + class TaskListViewCell extends ListCell { + + public TaskListViewCell() { + } + + @Override + protected void updateItem(ReadOnlyTask task, boolean empty) { + super.updateItem(task, empty); + + if (empty || task == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(TaskCard.load(task, getIndex() + 1).getLayout()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/seedu/address/ui/Ui.java b/src/main/java/seedu/gtd/ui/Ui.java similarity index 88% rename from src/main/java/seedu/address/ui/Ui.java rename to src/main/java/seedu/gtd/ui/Ui.java index e6a67fe8c027..39285dfef671 100644 --- a/src/main/java/seedu/address/ui/Ui.java +++ b/src/main/java/seedu/gtd/ui/Ui.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.gtd.ui; import javafx.stage.Stage; diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/gtd/ui/UiManager.java similarity index 81% rename from src/main/java/seedu/address/ui/UiManager.java rename to src/main/java/seedu/gtd/ui/UiManager.java index 4a4dba3a2f6e..30bf80953e5c 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/seedu/gtd/ui/UiManager.java @@ -1,4 +1,4 @@ -package seedu.address.ui; +package seedu.gtd.ui; import com.google.common.eventbus.Subscribe; import javafx.application.Platform; @@ -6,17 +6,17 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.image.Image; import javafx.stage.Stage; -import seedu.address.MainApp; -import seedu.address.commons.core.ComponentManager; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.commons.events.ui.JumpToListRequestEvent; -import seedu.address.commons.events.ui.PersonPanelSelectionChangedEvent; -import seedu.address.commons.events.ui.ShowHelpRequestEvent; -import seedu.address.commons.util.StringUtil; -import seedu.address.logic.Logic; -import seedu.address.model.UserPrefs; +import seedu.gtd.MainApp; +import seedu.gtd.commons.core.ComponentManager; +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.core.LogsCenter; +import seedu.gtd.commons.events.storage.DataSavingExceptionEvent; +import seedu.gtd.commons.events.ui.JumpToListRequestEvent; +import seedu.gtd.commons.events.ui.TaskPanelSelectionChangedEvent; +import seedu.gtd.commons.events.ui.ShowHelpRequestEvent; +import seedu.gtd.commons.util.StringUtil; +import seedu.gtd.logic.Logic; +import seedu.gtd.model.UserPrefs; import java.util.logging.Logger; @@ -25,8 +25,10 @@ */ public class UiManager extends ComponentManager implements Ui { private static final Logger logger = LogsCenter.getLogger(UiManager.class); - private static final String ICON_APPLICATION = "/images/address_book_32.png"; + // @@author A0139072H + private static final String ICON_APPLICATION = "/images/tary.png"; + //@@author addressbook-level4 private Logic logic; private Config config; private UserPrefs prefs; @@ -114,13 +116,13 @@ private void handleShowHelpEvent(ShowHelpRequestEvent event) { @Subscribe private void handleJumpToListRequestEvent(JumpToListRequestEvent event) { logger.info(LogsCenter.getEventHandlingLogMessage(event)); - mainWindow.getPersonListPanel().scrollTo(event.targetIndex); + mainWindow.getTaskListPanel().scrollTo(event.targetIndex); } @Subscribe - private void handlePersonPanelSelectionChangedEvent(PersonPanelSelectionChangedEvent event){ + private void handleTaskPanelSelectionChangedEvent(TaskPanelSelectionChangedEvent event){ logger.info(LogsCenter.getEventHandlingLogMessage(event)); - mainWindow.loadPersonPage(event.getNewSelection()); + mainWindow.loadTaskPage(event.getNewSelection()); } } diff --git a/src/main/java/seedu/address/ui/UiPart.java b/src/main/java/seedu/gtd/ui/UiPart.java similarity index 94% rename from src/main/java/seedu/address/ui/UiPart.java rename to src/main/java/seedu/gtd/ui/UiPart.java index 0a4ceb33e9b7..176162478686 100644 --- a/src/main/java/seedu/address/ui/UiPart.java +++ b/src/main/java/seedu/gtd/ui/UiPart.java @@ -1,13 +1,13 @@ -package seedu.address.ui; +package seedu.gtd.ui; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; import javafx.stage.Stage; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.BaseEvent; -import seedu.address.commons.util.AppUtil; +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.events.BaseEvent; +import seedu.gtd.commons.util.AppUtil; /** * Base class for UI parts. diff --git a/src/main/java/seedu/address/ui/UiPartLoader.java b/src/main/java/seedu/gtd/ui/UiPartLoader.java similarity index 97% rename from src/main/java/seedu/address/ui/UiPartLoader.java rename to src/main/java/seedu/gtd/ui/UiPartLoader.java index f880685a5b15..d18d877fdee7 100644 --- a/src/main/java/seedu/address/ui/UiPartLoader.java +++ b/src/main/java/seedu/gtd/ui/UiPartLoader.java @@ -1,10 +1,10 @@ -package seedu.address.ui; +package seedu.gtd.ui; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; -import seedu.address.MainApp; +import seedu.gtd.MainApp; /** * A utility class to load UiParts from FXML files. diff --git a/src/main/resources/images/tary.png b/src/main/resources/images/tary.png new file mode 100644 index 000000000000..c6f7cadb69f7 Binary files /dev/null and b/src/main/resources/images/tary.png differ diff --git a/src/main/resources/view/CommandBox.fxml b/src/main/resources/view/CommandBox.fxml index 575de420b994..242b613f836c 100644 --- a/src/main/resources/view/CommandBox.fxml +++ b/src/main/resources/view/CommandBox.fxml @@ -3,7 +3,7 @@ + fx:controller="seedu.gtd.ui.CommandBox" stylesheets="@DarkTheme.css"> diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 8043b344253a..b8d58c8bfb89 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -1,31 +1,31 @@ .background { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#D4C390, 100%); } .label { -fx-font-size: 11pt; - -fx-font-family: "Segoe UI Semibold"; + -fx-font-family: "Calibri"; -fx-text-fill: #555555; -fx-opacity: 0.9; } .label-bright { -fx-font-size: 11pt; - -fx-font-family: "Segoe UI Semibold"; + -fx-font-family: "Calibri"; -fx-text-fill: white; -fx-opacity: 1; } .label-header { -fx-font-size: 32pt; - -fx-font-family: "Segoe UI Light"; + -fx-font-family: "Calibri"; -fx-text-fill: white; -fx-opacity: 1; } .text-field { -fx-font-size: 12pt; - -fx-font-family: "Segoe UI Semibold"; + -fx-font-family: "Calibri"; } .tab-pane { @@ -93,17 +93,38 @@ } .list-cell .label { - -fx-text-fill: #010504; + /*-fx-text-fill: #010504;*/ +} + +.cell_priority_label { + -fx-font-size: 20px; + -fx-text-fill: derive(green, 20%); + -fx-stroke: black; + -fx-stroke-width: 20; } .cell_big_label { - -fx-font-size: 16px; + -fx-font-size: 20px; + -fx-fill: red; -fx-text-fill: #010504; } +// @@author A0139072H +.cell_date_label { + -fx-font-size: 15px; + -fx-text-fill: #174157; +} + +.cell_check_label { + -fx-font-size: 20px; + -fx-text-fill: derive(red,20%); +} + +// @@author addressbook-level4 .cell_small_label { - -fx-font-size: 11px; - -fx-text-fill: #010504; + -fx-font-size: 13px; + -fx-fill: red; + /*-fx-text-fill: #020605;*/ } .anchor-pane { @@ -167,7 +188,7 @@ .menu-bar .label { -fx-font-size: 14pt; - -fx-font-family: "Segoe UI Light"; + -fx-font-family: "Calibri"; -fx-text-fill: white; -fx-opacity: 0.9; } @@ -283,6 +304,6 @@ -fx-text-fill: #F70D1A; } -#filterField, #personListPanel, #personWebpage { +#filterField, #taskListPanel, #taskWebpage { -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0); } \ No newline at end of file diff --git a/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml b/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml index bc761118235a..f8b9b30c16bd 100644 --- a/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml +++ b/src/main/resources/view/DefaultBrowserPlaceHolderScreen.fxml @@ -7,10 +7,11 @@ - diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml deleted file mode 100644 index 13d4b149651b..000000000000 --- a/src/main/resources/view/PersonListCard.fxml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml index cc650d739e22..e156f40861ea 100644 --- a/src/main/resources/view/ResultDisplay.fxml +++ b/src/main/resources/view/ResultDisplay.fxml @@ -3,7 +3,7 @@ + fx:controller="seedu.gtd.ui.ResultDisplay"> diff --git a/src/main/resources/view/StatusBarFooter.fxml b/src/main/resources/view/StatusBarFooter.fxml index 2656558b6eb7..2c6bca15940d 100644 --- a/src/main/resources/view/StatusBarFooter.fxml +++ b/src/main/resources/view/StatusBarFooter.fxml @@ -1,7 +1,7 @@ - + diff --git a/src/main/resources/view/TaskListCard.fxml b/src/main/resources/view/TaskListCard.fxml new file mode 100644 index 000000000000..732ca7338efe --- /dev/null +++ b/src/main/resources/view/TaskListCard.fxml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/TaskListPanel.fxml similarity index 59% rename from src/main/resources/view/PersonListPanel.fxml rename to src/main/resources/view/TaskListPanel.fxml index 000c4c999b65..8c8cb25759a2 100644 --- a/src/main/resources/view/PersonListPanel.fxml +++ b/src/main/resources/view/TaskListPanel.fxml @@ -3,12 +3,12 @@ - + - + diff --git a/src/test/data/ConfigUtilTest/SomeFile.json b/src/test/data/ConfigUtilTest/SomeFile.json new file mode 100644 index 000000000000..ec747fa47ddb --- /dev/null +++ b/src/test/data/ConfigUtilTest/SomeFile.json @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/src/test/data/JsonUserPrefsStorageTest/SomeFile.json b/src/test/data/JsonUserPrefsStorageTest/SomeFile.json new file mode 100644 index 000000000000..ec747fa47ddb --- /dev/null +++ b/src/test/data/JsonUserPrefsStorageTest/SomeFile.json @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/src/test/data/ManualTesting/SampleData.xml b/src/test/data/ManualTesting/SampleData.xml new file mode 100644 index 000000000000..0cc098fd07af --- /dev/null +++ b/src/test/data/ManualTesting/SampleData.xml @@ -0,0 +1,411 @@ + + + + CS1001 Tutorial 4 + nil + 08/11/2016 19:00 +
NUS
+ 2 + false +
+ + Buy birthday cake + nil + 09/11/2016 19:00 +
Nex
+ 3 + false +
+ + Finish poster + nil + 10/11/2016 12:00 +
NUS
+ 5 + false +
+ + Clear out drawers + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Wash the dishes + nil + 08/11/2016 19:52 +
none
+ 4 + false +
+ + Buy eggs + nil + 08/11/2016 19:52 +
Giant
+ 5 + false +
+ + Vacuum floor + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Write angry blog post + nil + 08/11/2016 19:52 +
none
+ 2 + false +
+ + Cook lunch for friends + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Cook friends for lunch + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Replace old cabinet + nil + 08/11/2016 19:52 +
none
+ 4 + false +
+ + Change lightbulb + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Call mum + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Finish updating resume + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Print letter + nil + 08/11/2016 19:52 +
none
+ 1 + false +
+ + Submit insurance forms + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Tidy work desk + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Do a few sets on google code jam + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Buy new charging cable + nil + 08/11/2016 19:52 +
Nex
+ 5 + false +
+ + Borrow Tennis shoes from Shane + nil + 08/11/2016 19:52 +
NUS
+ 2 + false +
+ + Watch GEM1917 webcast + nil + 08/11/2016 19:52 +
NUS
+ 5 + false +
+ + Prepare for interview + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Buy EE2020 textbook + nil + 08/11/2016 19:52 +
NUS
+ 5 + false +
+ + Replace faulty access card + nil + 08/11/2016 19:52 +
NUS
+ 5 + false +
+ + Sign up to donate blood + nil + 08/11/2016 19:52 +
Tan Tock Seng
+ 4 + false +
+ + Maroon 5 Concert + nil + 08/11/2016 19:52 +
Marina Bay Sands
+ 5 + false +
+ + Practice Beethoven's 9th + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Email supervisor + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + CS2103 Tutorial 5 + nil + 08/11/2016 19:52 +
NUS
+ 5 + false +
+ + 20 page monthly report + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Pick up dad from the station + nil + 08/11/2016 19:52 +
One north mrt
+ 2 + false +
+ + Dentist appointment + nil + 08/11/2016 19:52 +
Mount Elizabeth
+ 5 + false +
+ + EE2021 finals + nil + 08/11/2016 19:52 +
NUS
+ 5 + false +
+ + CS1020 PE + nil + 08/11/2016 19:52 +
NUS
+ 3 + false +
+ + Return library books + nil + 08/11/2016 19:52 +
NUS
+ 5 + false +
+ + Learn how to tie shoes + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Fix parser bug + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Write conference speech + nil + 08/11/2016 19:52 +
none
+ 4 + false +
+ + Wash Dog + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Wash car + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Sell watch at pawn shop + nil + 08/11/2016 19:52 +
AMK Hub
+ 2 + false +
+ + Marinate Turkey + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Volunteer at charity sales stand + nil + 08/11/2016 19:52 +
NTU
+ 5 + false +
+ + Finish writing cover letter + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Mail postcards + nil + 08/11/2016 19:52 +
none
+ 4 + false +
+ + Buy christmas presents + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Rearrange closet + nil + 08/11/2016 19:52 +
none
+ 3 + false +
+ + Wash windows + nil + 08/11/2016 19:52 +
none
+ 5 + false +
+ + Drown sorrows + 08/11/2016 23:59 + 09/11/2016 23:52 +
Clarke Quay
+ 5 + false +
+ + Think of family + nil + 08/11/2016 19:52 +
Ridge View Residential College
+ 3 + false +
+ + Late Submission + nil + 08/11/2016 00:10 +
School Of Computing
+ 5 + false +
+
diff --git a/src/test/data/ManualTesting/TestScript.md b/src/test/data/ManualTesting/TestScript.md new file mode 100644 index 000000000000..9f303f212b0c --- /dev/null +++ b/src/test/data/ManualTesting/TestScript.md @@ -0,0 +1,102 @@ +# Test Script + +## Load Sample Data +1. Download the zip file [F10-C3][Tary].zip +2. Extract all contents of the zip file into the same folder, if done right, the following should be in the same folder: + * Config.json + * Preferences.json + * [F10-C3][Tary].jar + * folder named 'data' with only 1 file, 'sampleData.xml' +3. Launch [F10-C3][Tary].jar + + +## Script +### 1. Add Command +* Add a floating task: `add buy coffee`
+ > adds floating task with name: buy coffee, priority set as default (1) and all other fields: nil. +* Add an event task: `add nus hackathon s/saturday d/sunday`
+ > adds task with name: nus hackathon, start date is next Saturday of the testing, and end date is next Sunday of testing.
+ > both are in the format: dd/mm/yyyy hh:mm +* Add a deadline task: `add CS2103 tutorial d/tomorrow`
+ > start date not specified but end date (which is deadline) is. +* Add a full task: `add write letter a/NUS s/today d/tomorrow p/5 t/formal`
+ > all fields in task card are fielded with given data +* Add a full task with a different order: `add write letter d/friday s/thursday t/tomorrow p/2`
+ > same as above +* Add a task with optional parameters: `add clean room a/home`
+ +### 2. Done Command +* Mark a task as done `done 1`
+ > task card will change task at index 1 from [X] to [O] +* Mark a task as done `done 4`
+ > same as above at index 4 +* Mark a task as done `done 6`
+ > same as above at index 6 +
+ +### 3. List Command +* List all the done tasks: `list done`
+ > returns task cards that were previously at index 1,4 and 6 +* List all the tasks not done yet: `list`
+ > returns all task cards without index 1,4 and 6 +
+ +### 4. Delete Command +* delete task: `delete 3`
+ > task with index 3 is removed from the list +* delete task: `delete 5`
+ > task with index 5 is removed from the list +* delete task: `delete 2`
+ > task with index 2 is removed from the list +
+ +### 5. Undo Command +* undo delete of task 2: `undo` +* undo delete of task 5: `undo` +* undo delete of task 3: `undo` +
+ +### 6. Edit Command +* add task: `add supermarket trip d/today p/3 a/cold storage` +* edit task (single parameter) at index 3: `edit 3 p/1`
+ > priority of index 3 bumped down +* edit task (multiple parameter) at the index of the added task: `edit INDEX p/5 a/NTUC`
+ > change of location and priority reflected on this task card +
+ +### 7. Select Command +* select the supermarket task: `select INDEX`
+ > displays the location of the task on google maps at the browser panel +
+ +### 8. Find Command +* find task called 'homework': `find homework`
+ > only returns list of tasks with homework in the name +* find tasks tagged with 'homework': `find t/homework`
+ > only returns list of tasks with a tag called homework +* find tasks with priority 5: `find p/5`
+ > returns most urgent tasks with max priority 5 +* find tasks due today: `find d/today`
+ > returns all tasks due today +
+ +### 9. Help Command +* open help: `help` +
+ +### 10. Clear Command +* delete all tasks: `clear` +
+ +### 11. setPath Command +* set storage to specified path: `setPath data/newfile.xml` +
+ +### 12. Exit Command +* exit the app: `exit` + +
+ + + + diff --git a/src/test/data/XmlAddressBookStorageTest/SomeFile.xml b/src/test/data/XmlAddressBookStorageTest/SomeFile.xml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/data/XmlUtilTest/tempAddressBook.xml b/src/test/data/XmlUtilTest/tempAddressBook.xml index 41eeb8eb391a..264d24355ef9 100644 --- a/src/test/data/XmlUtilTest/tempAddressBook.xml +++ b/src/test/data/XmlUtilTest/tempAddressBook.xml @@ -1,14 +1,13 @@ - + 1 - John - Doe + John - + Friends diff --git a/src/test/data/XmlUtilTest/validAddressBook.xml b/src/test/data/XmlUtilTest/validAddressBook.xml index eafca730fb1e..2e736caac96c 100644 --- a/src/test/data/XmlUtilTest/validAddressBook.xml +++ b/src/test/data/XmlUtilTest/validAddressBook.xml @@ -1,57 +1,74 @@ - + Hans Muster - 9482424 - hans@google.com + 9482424
4th street
-
- + 4 + startDatestartDate + + Ruth Mueller - 87249245 - ruth@google.com + 87249245
81th street
-
- + 2 + + + + Heinz Kurz - 95352563 - heinz@yahoo.com + 95352563
wall street
-
- + 1 + + + + Cornelia Meier - 87652533 - cornelia@google.com + 87652533
10th street
-
- + 1 + + + + Werner Meyer - 9482224 - werner@gmail.com + 9482224
michegan ave
-
- + 1 + + + + Lydia Kunz - 9482427 - lydia@gmail.com + 9482427
little tokyo
-
- + 1 + + + + Anna Best - 9482442 - anna@google.com + 9482442
4th street
-
- + 4 + + + + Stefan Meier - 8482424 - stefan@mail.com + 8482424
little india
-
- + 1 + + + + Martin Mueller - 8482131 - hans@google.com + 8482131
chicago ave
-
+ 1 + + +
diff --git a/src/test/java/guitests/AddCommandTest.java b/src/test/java/guitests/AddCommandTest.java index 3b2e1844bd0d..f548768b8771 100644 --- a/src/test/java/guitests/AddCommandTest.java +++ b/src/test/java/guitests/AddCommandTest.java @@ -1,53 +1,76 @@ package guitests; -import guitests.guihandles.PersonCardHandle; +import guitests.guihandles.TaskCardHandle; import org.junit.Test; -import seedu.address.logic.commands.AddCommand; -import seedu.address.commons.core.Messages; -import seedu.address.testutil.TestPerson; -import seedu.address.testutil.TestUtil; + +import seedu.gtd.commons.core.Messages; +import seedu.gtd.logic.commands.AddCommand; +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; import static org.junit.Assert.assertTrue; public class AddCommandTest extends AddressBookGuiTest { - + @Test public void add() { - //add one person - TestPerson[] currentList = td.getTypicalPersons(); - TestPerson personToAdd = td.hoon; - assertAddSuccess(personToAdd, currentList); - currentList = TestUtil.addPersonsToList(currentList, personToAdd); - - //add another person - personToAdd = td.ida; - assertAddSuccess(personToAdd, currentList); - currentList = TestUtil.addPersonsToList(currentList, personToAdd); - - //add duplicate person + //add one task + //add success modified takes into account date format changes when using Natty + TestTask[] currentList = td.getTypicalTasks(); + TestTask taskToAdd = td.hoon; + TestTask taskChanged = td.hoonChanged; + assertAddSuccessModified(taskToAdd, taskChanged, currentList); + //assertAddSuccess(taskToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, taskChanged); + System.out.println("HOON ADDED"); + + //add another task + taskToAdd = td.ida; + taskChanged = td.idaChanged; + assertAddSuccessModified(taskToAdd, taskChanged, currentList); + //assertAddSuccess(taskToAdd, currentList); + currentList = TestUtil.addTasksToList(currentList, taskChanged); + System.out.println("IDA ADDED"); + + //add duplicate task commandBox.runCommand(td.hoon.getAddCommand()); - assertResultMessage(AddCommand.MESSAGE_DUPLICATE_PERSON); - assertTrue(personListPanel.isListMatching(currentList)); + System.out.println(AddCommand.MESSAGE_DUPLICATE_TASK); + assertResultMessage(AddCommand.MESSAGE_DUPLICATE_TASK); + assertTrue(taskListPanel.isListMatching(currentList)); + System.out.println("DUPLICATE REJECTED"); //add to empty list commandBox.runCommand("clear"); - assertAddSuccess(td.alice); + assertAddSuccessModified(td.alice, td.aliceChanged); //invalid command commandBox.runCommand("adds Johnny"); assertResultMessage(Messages.MESSAGE_UNKNOWN_COMMAND); } - private void assertAddSuccess(TestPerson personToAdd, TestPerson... currentList) { - commandBox.runCommand(personToAdd.getAddCommand()); + private void assertAddSuccess(TestTask taskToAdd, TestTask... currentList) { + commandBox.runCommand(taskToAdd.getAddCommand()); + + //confirm the new card contains the right data + TaskCardHandle addedCard = taskListPanel.navigateToTask(taskToAdd.getName().fullName); + System.out.println("FULL NAME: " + taskToAdd.getName().fullName); + assertMatching(taskToAdd, addedCard); + + //confirm the list now contains all previous tasks plus the new task + TestTask[] expectedList = TestUtil.addTasksToList(currentList, taskToAdd); + assertTrue(taskListPanel.isListMatching(expectedList)); + } + + private void assertAddSuccessModified(TestTask taskToAdd, TestTask taskChanged, TestTask... currentList) { + commandBox.runCommand(taskToAdd.getAddCommand()); //confirm the new card contains the right data - PersonCardHandle addedCard = personListPanel.navigateToPerson(personToAdd.getName().fullName); - assertMatching(personToAdd, addedCard); + TaskCardHandle addedCard = taskListPanel.navigateToTask(taskToAdd.getName().fullName); + assertMatching(taskChanged, addedCard); - //confirm the list now contains all previous persons plus the new person - TestPerson[] expectedList = TestUtil.addPersonsToList(currentList, personToAdd); - assertTrue(personListPanel.isListMatching(expectedList)); + //confirm the list now contains all previous tasks plus the new task + TestTask[] expectedList = TestUtil.addTasksToList(currentList, taskChanged); + assertTrue(taskListPanel.isListMatching(expectedList)); } } diff --git a/src/test/java/guitests/AddressBookGuiTest.java b/src/test/java/guitests/AddressBookGuiTest.java index 35734932f11c..0be754758e9c 100644 --- a/src/test/java/guitests/AddressBookGuiTest.java +++ b/src/test/java/guitests/AddressBookGuiTest.java @@ -8,12 +8,13 @@ import org.junit.Rule; import org.junit.rules.TestName; import org.testfx.api.FxToolkit; -import seedu.address.TestApp; -import seedu.address.commons.core.EventsCenter; -import seedu.address.model.AddressBook; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.testutil.TestUtil; -import seedu.address.testutil.TypicalTestPersons; + +import seedu.gtd.TestApp; +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.testutil.TestUtil; +import seedu.gtd.testutil.TypicalTestTasks; import java.util.concurrent.TimeoutException; @@ -31,7 +32,7 @@ public abstract class AddressBookGuiTest { TestApp testApp; - protected TypicalTestPersons td = new TypicalTestPersons(); + protected TypicalTestTasks td = new TypicalTestTasks(); /* * Handles to GUI elements present at the start up are created in advance @@ -39,7 +40,7 @@ public abstract class AddressBookGuiTest { */ protected MainGuiHandle mainGui; protected MainMenuHandle mainMenu; - protected PersonListPanelHandle personListPanel; + protected TaskListPanelHandle taskListPanel; protected ResultDisplayHandle resultDisplay; protected CommandBoxHandle commandBox; private Stage stage; @@ -59,7 +60,7 @@ public void setup() throws Exception { FxToolkit.setupStage((stage) -> { mainGui = new MainGuiHandle(new GuiRobot(), stage); mainMenu = mainGui.getMainMenu(); - personListPanel = mainGui.getPersonListPanel(); + taskListPanel = mainGui.getTaskListPanel(); resultDisplay = mainGui.getResultDisplay(); commandBox = mainGui.getCommandBox(); this.stage = stage; @@ -77,7 +78,7 @@ public void setup() throws Exception { */ protected AddressBook getInitialData() { AddressBook ab = TestUtil.generateEmptyAddressBook(); - TypicalTestPersons.loadAddressBookWithSampleData(ab); + TypicalTestTasks.loadAddressBookWithSampleData(ab); return ab; } @@ -94,17 +95,17 @@ public void cleanup() throws TimeoutException { } /** - * Asserts the person shown in the card is same as the given person + * Asserts the task shown in the card is same as the given task */ - public void assertMatching(ReadOnlyPerson person, PersonCardHandle card) { - assertTrue(TestUtil.compareCardAndPerson(card, person)); + public void assertMatching(ReadOnlyTask task, TaskCardHandle card) { + assertTrue(TestUtil.compareCardAndTask(card, task)); } /** - * Asserts the size of the person list is equal to the given number. + * Asserts the size of the task list is equal to the given number. */ protected void assertListSize(int size) { - int numberOfPeople = personListPanel.getNumberOfPeople(); + int numberOfPeople = taskListPanel.getNumberOfPeople(); assertEquals(size, numberOfPeople); } diff --git a/src/test/java/guitests/ClearCommandTest.java b/src/test/java/guitests/ClearCommandTest.java index 9d52b427659c..888b7a018259 100644 --- a/src/test/java/guitests/ClearCommandTest.java +++ b/src/test/java/guitests/ClearCommandTest.java @@ -10,12 +10,12 @@ public class ClearCommandTest extends AddressBookGuiTest { public void clear() { //verify a non-empty list can be cleared - assertTrue(personListPanel.isListMatching(td.getTypicalPersons())); + assertTrue(taskListPanel.isListMatching(td.getTypicalTasks())); assertClearCommandSuccess(); //verify other commands can work after a clear command commandBox.runCommand(td.hoon.getAddCommand()); - assertTrue(personListPanel.isListMatching(td.hoon)); + assertTrue(taskListPanel.isListMatching(td.hoonChanged)); commandBox.runCommand("delete 1"); assertListSize(0); @@ -26,6 +26,6 @@ public void clear() { private void assertClearCommandSuccess() { commandBox.runCommand("clear"); assertListSize(0); - assertResultMessage("Address book has been cleared!"); + assertResultMessage("Task List has been cleared!"); } } diff --git a/src/test/java/guitests/CommandBoxTest.java b/src/test/java/guitests/CommandBoxTest.java index 1379198bf8b0..50550eb5d9e2 100644 --- a/src/test/java/guitests/CommandBoxTest.java +++ b/src/test/java/guitests/CommandBoxTest.java @@ -9,6 +9,8 @@ public class CommandBoxTest extends AddressBookGuiTest { @Test public void commandBox_commandSucceeds_textCleared() { commandBox.runCommand(td.benson.getAddCommand()); + System.out.println("Entered " + td.benson.getAddCommand().toString()); + System.out.println("Expected blank got " +commandBox.getCommandInput()); assertEquals(commandBox.getCommandInput(), ""); } diff --git a/src/test/java/guitests/DeleteCommandTest.java b/src/test/java/guitests/DeleteCommandTest.java index 10c7b9e0dbea..6453d1b2a278 100644 --- a/src/test/java/guitests/DeleteCommandTest.java +++ b/src/test/java/guitests/DeleteCommandTest.java @@ -1,11 +1,12 @@ package guitests; import org.junit.Test; -import seedu.address.testutil.TestPerson; -import seedu.address.testutil.TestUtil; + +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; import static org.junit.Assert.assertTrue; -import static seedu.address.logic.commands.DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS; +import static seedu.gtd.logic.commands.DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS; public class DeleteCommandTest extends AddressBookGuiTest { @@ -13,42 +14,42 @@ public class DeleteCommandTest extends AddressBookGuiTest { public void delete() { //delete the first in the list - TestPerson[] currentList = td.getTypicalPersons(); + TestTask[] currentList = td.getTypicalTasks(); int targetIndex = 1; assertDeleteSuccess(targetIndex, currentList); //delete the last in the list - currentList = TestUtil.removePersonFromList(currentList, targetIndex); + currentList = TestUtil.removeTaskFromList(currentList, targetIndex); targetIndex = currentList.length; assertDeleteSuccess(targetIndex, currentList); //delete from the middle of the list - currentList = TestUtil.removePersonFromList(currentList, targetIndex); + currentList = TestUtil.removeTaskFromList(currentList, targetIndex); targetIndex = currentList.length/2; assertDeleteSuccess(targetIndex, currentList); //invalid index commandBox.runCommand("delete " + currentList.length + 1); - assertResultMessage("The person index provided is invalid"); + assertResultMessage("The task index provided is invalid"); } /** - * Runs the delete command to delete the person at specified index and confirms the result is correct. - * @param targetIndexOneIndexed e.g. to delete the first person in the list, 1 should be given as the target index. - * @param currentList A copy of the current list of persons (before deletion). + * Runs the delete command to delete the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to delete the first task in the list, 1 should be given as the target index. + * @param currentList A copy of the current list of tasks (before deletion). */ - private void assertDeleteSuccess(int targetIndexOneIndexed, final TestPerson[] currentList) { - TestPerson personToDelete = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing - TestPerson[] expectedRemainder = TestUtil.removePersonFromList(currentList, targetIndexOneIndexed); + private void assertDeleteSuccess(int targetIndexOneIndexed, final TestTask[] currentList) { + TestTask taskToDelete = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestTask[] expectedRemainder = TestUtil.removeTaskFromList(currentList, targetIndexOneIndexed); commandBox.runCommand("delete " + targetIndexOneIndexed); - //confirm the list now contains all previous persons except the deleted person - assertTrue(personListPanel.isListMatching(expectedRemainder)); + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(expectedRemainder)); //confirm the result message is correct - assertResultMessage(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); + assertResultMessage(String.format(MESSAGE_DELETE_TASK_SUCCESS, taskToDelete)); } } diff --git a/src/test/java/guitests/EditCommandTest.java b/src/test/java/guitests/EditCommandTest.java new file mode 100644 index 000000000000..347180e3dd77 --- /dev/null +++ b/src/test/java/guitests/EditCommandTest.java @@ -0,0 +1,94 @@ +//@@author A0146130W + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; +import seedu.gtd.testutil.TestUtil; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.EditCommand.MESSAGE_EDIT_TASK_SUCCESS; + +public class EditCommandTest extends AddressBookGuiTest { + + @Test + public void edit() { + + //edit the priority of the first task + TestTask[] currentList = td.getTypicalTasks(); + int targetIndex = 1; + String change = "p/4"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the dueDate of the last in the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + targetIndex = currentList.length; + change = "d/2"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the name task from the middle of the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + targetIndex = currentList.length/2; + change = "Cook lunch for friends"; + assertEditSuccess(targetIndex, change, currentList); + + //edit the address task from the middle of the list + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + change = "a/Little India"; + assertEditSuccess(targetIndex, change, currentList); + + /* + //edit everything at once + currentList = TestUtil.editTaskInList(currentList, targetIndex, change, currentList[targetIndex-1]); + change = "Cook friends for lunch d/midnight a/SMU p/5"; + String change1 = "Cook friends for lunch"; + String change2 = "d/midnight"; + String change3 = "a/SMU"; + String change4 = "p/5"; + String[] changes = {change1, change2, change3, change4}; + assertMultipleEditSuccess(targetIndex, change, currentList, changes); + */ + + //invalid index + commandBox.runCommand("edit " + currentList.length + 1 + " Invalid"); + assertResultMessage("The task index provided is invalid"); + + } + + /** + * Runs the edit command to edit the task at specified index and confirms the result is correct. + * @param targetIndexOneIndexed e.g. to edit the first task in the list, 1 should be given as the target index. + * @param currentList A copy of the current list of tasks (before editing) + * @param change: contains detail with appropriate prefix that the user wants to edit into a task with index targetIndexOneIndexed. + * + */ + private void assertEditSuccess(int targetIndexOneIndexed, String change, final TestTask[] currentList) { + TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestTask[] expectedRemainder = TestUtil.editTaskInList(currentList, targetIndexOneIndexed, change, taskToEdit); + commandBox.runCommand("edit " + targetIndexOneIndexed + " " + change); + + assertTrue(taskListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_EDIT_TASK_SUCCESS, expectedRemainder[targetIndexOneIndexed-1])); + } + + /* + private void assertMultipleEditSuccess(int targetIndexOneIndexed, String change, TestTask[] currentList, String[] changeArr) { + TestTask taskToEdit = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + + for(String c: changeArr) { + currentList = TestUtil.editTaskInList(currentList, targetIndexOneIndexed, c, taskToEdit); + } + TestTask[] expectedRemainder = currentList; + + commandBox.runCommand("edit " + targetIndexOneIndexed + " " + change); + + assertTrue(taskListPanel.isListMatching(expectedRemainder)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_EDIT_TASK_SUCCESS, expectedRemainder[targetIndexOneIndexed-1])); + } + */ +} diff --git a/src/test/java/guitests/FindCommandTest.java b/src/test/java/guitests/FindCommandTest.java index 441a6dbed666..7354a653d366 100644 --- a/src/test/java/guitests/FindCommandTest.java +++ b/src/test/java/guitests/FindCommandTest.java @@ -1,8 +1,9 @@ package guitests; import org.junit.Test; -import seedu.address.commons.core.Messages; -import seedu.address.testutil.TestPerson; + +import seedu.gtd.commons.core.Messages; +import seedu.gtd.testutil.TestTask; import static org.junit.Assert.assertTrue; @@ -30,10 +31,10 @@ public void find_invalidCommand_fail() { assertResultMessage(Messages.MESSAGE_UNKNOWN_COMMAND); } - private void assertFindResult(String command, TestPerson... expectedHits ) { + private void assertFindResult(String command, TestTask... expectedHits ) { commandBox.runCommand(command); assertListSize(expectedHits.length); - assertResultMessage(expectedHits.length + " persons listed!"); - assertTrue(personListPanel.isListMatching(expectedHits)); + assertResultMessage(expectedHits.length + " tasks listed!"); + assertTrue(taskListPanel.isListMatching(expectedHits)); } } diff --git a/src/test/java/guitests/GuiRobot.java b/src/test/java/guitests/GuiRobot.java index 44aa9edb48aa..c3f29c2af6c4 100644 --- a/src/test/java/guitests/GuiRobot.java +++ b/src/test/java/guitests/GuiRobot.java @@ -1,8 +1,9 @@ package guitests; import javafx.scene.input.KeyCodeCombination; +import seedu.gtd.testutil.TestUtil; + import org.testfx.api.FxRobot; -import seedu.address.testutil.TestUtil; /** * Robot used to simulate user actions on the GUI. diff --git a/src/test/java/guitests/HelpWindowTest.java b/src/test/java/guitests/HelpWindowTest.java index 258d9d628d80..436c485f1efe 100644 --- a/src/test/java/guitests/HelpWindowTest.java +++ b/src/test/java/guitests/HelpWindowTest.java @@ -10,7 +10,7 @@ public class HelpWindowTest extends AddressBookGuiTest { @Test public void openHelpWindow() { - personListPanel.clickOnListView(); + taskListPanel.clickOnListView(); assertHelpWindowOpen(mainMenu.openHelpWindowUsingAccelerator()); diff --git a/src/test/java/guitests/SelectCommandTest.java b/src/test/java/guitests/SelectCommandTest.java index 5273552056ce..a043399f8d75 100644 --- a/src/test/java/guitests/SelectCommandTest.java +++ b/src/test/java/guitests/SelectCommandTest.java @@ -1,7 +1,8 @@ package guitests; import org.junit.Test; -import seedu.address.model.person.ReadOnlyPerson; + +import seedu.gtd.model.task.ReadOnlyTask; import static org.junit.Assert.assertEquals; @@ -9,25 +10,25 @@ public class SelectCommandTest extends AddressBookGuiTest { @Test - public void selectPerson_nonEmptyList() { + public void selectTask_nonEmptyList() { assertSelectionInvalid(10); //invalid index - assertNoPersonSelected(); + assertNoTaskSelected(); - assertSelectionSuccess(1); //first person in the list - int personCount = td.getTypicalPersons().length; - assertSelectionSuccess(personCount); //last person in the list - int middleIndex = personCount / 2; - assertSelectionSuccess(middleIndex); //a person in the middle of the list + assertSelectionSuccess(1); //first task in the list + int taskCount = td.getTypicalTasks().length; + assertSelectionSuccess(taskCount); //last task in the list + int middleIndex = taskCount / 2; + assertSelectionSuccess(middleIndex); //a task in the middle of the list - assertSelectionInvalid(personCount + 1); //invalid index - assertPersonSelected(middleIndex); //assert previous selection remains + assertSelectionInvalid(taskCount + 1); //invalid index + assertTaskSelected(middleIndex); //assert previous selection remains /* Testing other invalid indexes such as -1 should be done when testing the SelectCommand */ } @Test - public void selectPerson_emptyList(){ + public void selectTask_emptyList(){ commandBox.runCommand("clear"); assertListSize(0); assertSelectionInvalid(1); //invalid index @@ -35,24 +36,24 @@ public void selectPerson_emptyList(){ private void assertSelectionInvalid(int index) { commandBox.runCommand("select " + index); - assertResultMessage("The person index provided is invalid"); + assertResultMessage("The task index provided is invalid"); } private void assertSelectionSuccess(int index) { commandBox.runCommand("select " + index); - assertResultMessage("Selected Person: "+index); - assertPersonSelected(index); + assertResultMessage("Selected Task: "+index); + assertTaskSelected(index); } - private void assertPersonSelected(int index) { - assertEquals(personListPanel.getSelectedPersons().size(), 1); - ReadOnlyPerson selectedPerson = personListPanel.getSelectedPersons().get(0); - assertEquals(personListPanel.getPerson(index-1), selectedPerson); + private void assertTaskSelected(int index) { + assertEquals(taskListPanel.getSelectedTasks().size(), 1); + ReadOnlyTask selectedTask = taskListPanel.getSelectedTasks().get(0); + assertEquals(taskListPanel.getTask(index-1), selectedTask); //TODO: confirm the correct page is loaded in the Browser Panel } - private void assertNoPersonSelected() { - assertEquals(personListPanel.getSelectedPersons().size(), 0); + private void assertNoTaskSelected() { + assertEquals(taskListPanel.getSelectedTasks().size(), 0); } } diff --git a/src/test/java/guitests/UndoCommandTest.java b/src/test/java/guitests/UndoCommandTest.java new file mode 100644 index 000000000000..2e691df10c31 --- /dev/null +++ b/src/test/java/guitests/UndoCommandTest.java @@ -0,0 +1,93 @@ +//@@author A0146130W + +package guitests; + +import org.junit.Test; + +import seedu.gtd.testutil.TestTask; + +import static org.junit.Assert.assertTrue; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_SUCCESS; +import static seedu.gtd.logic.commands.UndoCommand.MESSAGE_UNDO_LIMIT_REACHED; + +import java.util.Stack;; + +public class UndoCommandTest extends AddressBookGuiTest { + + @Test + public void undo() { + + //undo the addition of the first task + TestTask[] currentList = td.getTypicalTasks(); + Stack previousList = new Stack(); + previousList.push(currentList); + commandBox.runCommand(td.george.getAddCommand()); + assertUndoSuccess(previousList.pop()); + + //undo editing the dueDate of the last task in the list + int targetIndex = currentList.length; + String change = "d/2"; + previousList.push(currentList); + commandBox.runCommand("edit " + targetIndex + " " + change); + assertUndoSuccess(previousList.pop()); + + //undo deleting a task from the middle of the list + targetIndex = currentList.length/2; + previousList.push(currentList); + commandBox.runCommand("delete " + targetIndex); + assertUndoSuccess(previousList.pop()); + + //undo clearing list + previousList.push(currentList); + commandBox.runCommand("clear"); + assertUndoSuccess(previousList.pop()); + + //undo marking the middle task as done + previousList.push(currentList); + commandBox.runCommand("done " + targetIndex); + assertUndoSuccess(previousList.pop()); + + /* + //undo multiple times + previousList.push(currentList); + commandBox.runCommand("edit " + targetIndex + " " + change); + previousList.push(currentList); + commandBox.runCommand(td.george.getAddCommand()); + previousList.push(currentList); + commandBox.runCommand("delete " + targetIndex); + previousList.push(currentList); + commandBox.runCommand("done " + targetIndex); + previousList.push(currentList); + commandBox.runCommand("clear"); + assertMultipleUndoSuccess(previousList); + */ + } + + /** + * Runs the undo command to undo the last change to the task list + */ + private void assertUndoSuccess(final TestTask[] previousList) { + commandBox.runCommand("undo"); + + //confirm the list now contains all previous tasks except the deleted task + assertTrue(taskListPanel.isListMatching(previousList)); + + //confirm the result message is correct + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + + private void assertMultipleUndoSuccess(final Stack previousList) { + + //run undo multiple times and verify list each time + for(int i=1; i < previousList.size(); i++) { + commandBox.runCommand("undo"); + assertTrue(taskListPanel.isListMatching(previousList.pop())); + assertResultMessage(String.format(MESSAGE_SUCCESS)); + } + + //verify that the undo limit message is shown when undo limit is reached + commandBox.runCommand("undo"); + assertResultMessage(String.format(MESSAGE_UNDO_LIMIT_REACHED)); + } + +} diff --git a/src/test/java/guitests/guihandles/GuiHandle.java b/src/test/java/guitests/guihandles/GuiHandle.java index 5e7e0f6de911..f4e8b2eaaa0f 100644 --- a/src/test/java/guitests/guihandles/GuiHandle.java +++ b/src/test/java/guitests/guihandles/GuiHandle.java @@ -7,8 +7,8 @@ import javafx.scene.input.KeyCode; import javafx.stage.Stage; import javafx.stage.Window; -import seedu.address.TestApp; -import seedu.address.commons.core.LogsCenter; +import seedu.gtd.TestApp; +import seedu.gtd.commons.core.LogsCenter; import java.util.logging.Logger; diff --git a/src/test/java/guitests/guihandles/MainGuiHandle.java b/src/test/java/guitests/guihandles/MainGuiHandle.java index 45802c5135c7..360ca5251435 100644 --- a/src/test/java/guitests/guihandles/MainGuiHandle.java +++ b/src/test/java/guitests/guihandles/MainGuiHandle.java @@ -2,7 +2,7 @@ import guitests.GuiRobot; import javafx.stage.Stage; -import seedu.address.TestApp; +import seedu.gtd.TestApp; /** * Provides a handle for the main GUI. @@ -13,8 +13,8 @@ public MainGuiHandle(GuiRobot guiRobot, Stage primaryStage) { super(guiRobot, primaryStage, TestApp.APP_TITLE); } - public PersonListPanelHandle getPersonListPanel() { - return new PersonListPanelHandle(guiRobot, primaryStage); + public TaskListPanelHandle getTaskListPanel() { + return new TaskListPanelHandle(guiRobot, primaryStage); } public ResultDisplayHandle getResultDisplay() { diff --git a/src/test/java/guitests/guihandles/MainMenuHandle.java b/src/test/java/guitests/guihandles/MainMenuHandle.java index 0aeb047a0e1d..d6cc21cd4dc3 100644 --- a/src/test/java/guitests/guihandles/MainMenuHandle.java +++ b/src/test/java/guitests/guihandles/MainMenuHandle.java @@ -3,7 +3,7 @@ import guitests.GuiRobot; import javafx.scene.input.KeyCode; import javafx.stage.Stage; -import seedu.address.TestApp; +import seedu.gtd.TestApp; import java.util.Arrays; diff --git a/src/test/java/guitests/guihandles/PersonCardHandle.java b/src/test/java/guitests/guihandles/PersonCardHandle.java deleted file mode 100644 index fae22a45ae2f..000000000000 --- a/src/test/java/guitests/guihandles/PersonCardHandle.java +++ /dev/null @@ -1,63 +0,0 @@ -package guitests.guihandles; - -import guitests.GuiRobot; -import javafx.scene.Node; -import javafx.stage.Stage; -import seedu.address.model.person.ReadOnlyPerson; - -/** - * Provides a handle to a person card in the person list panel. - */ -public class PersonCardHandle extends GuiHandle { - private static final String NAME_FIELD_ID = "#name"; - private static final String ADDRESS_FIELD_ID = "#address"; - private static final String PHONE_FIELD_ID = "#phone"; - private static final String EMAIL_FIELD_ID = "#email"; - - private Node node; - - public PersonCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ - super(guiRobot, primaryStage, null); - this.node = node; - } - - protected String getTextFromLabel(String fieldId) { - return getTextFromLabel(fieldId, node); - } - - public String getFullName() { - return getTextFromLabel(NAME_FIELD_ID); - } - - public String getAddress() { - return getTextFromLabel(ADDRESS_FIELD_ID); - } - - public String getPhone() { - return getTextFromLabel(PHONE_FIELD_ID); - } - - public String getEmail() { - return getTextFromLabel(EMAIL_FIELD_ID); - } - - public boolean isSamePerson(ReadOnlyPerson person){ - return getFullName().equals(person.getName().fullName) && getPhone().equals(person.getPhone().value) - && getEmail().equals(person.getEmail().value) && getAddress().equals(person.getAddress().value); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof PersonCardHandle) { - PersonCardHandle handle = (PersonCardHandle) obj; - return getFullName().equals(handle.getFullName()) - && getAddress().equals(handle.getAddress()); //TODO: compare the rest - } - return super.equals(obj); - } - - @Override - public String toString() { - return getFullName() + " " + getAddress(); - } -} diff --git a/src/test/java/guitests/guihandles/PersonListPanelHandle.java b/src/test/java/guitests/guihandles/PersonListPanelHandle.java deleted file mode 100644 index 3451992cf735..000000000000 --- a/src/test/java/guitests/guihandles/PersonListPanelHandle.java +++ /dev/null @@ -1,172 +0,0 @@ -package guitests.guihandles; - - -import guitests.GuiRobot; -import javafx.geometry.Point2D; -import javafx.scene.Node; -import javafx.scene.control.ListView; -import javafx.stage.Stage; -import seedu.address.TestApp; -import seedu.address.model.person.Person; -import seedu.address.model.person.ReadOnlyPerson; -import seedu.address.testutil.TestUtil; - -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.junit.Assert.assertTrue; - -/** - * Provides a handle for the panel containing the person list. - */ -public class PersonListPanelHandle extends GuiHandle { - - public static final int NOT_FOUND = -1; - public static final String CARD_PANE_ID = "#cardPane"; - - private static final String PERSON_LIST_VIEW_ID = "#personListView"; - - public PersonListPanelHandle(GuiRobot guiRobot, Stage primaryStage) { - super(guiRobot, primaryStage, TestApp.APP_TITLE); - } - - public List getSelectedPersons() { - ListView personList = getListView(); - return personList.getSelectionModel().getSelectedItems(); - } - - public ListView getListView() { - return (ListView) getNode(PERSON_LIST_VIEW_ID); - } - - /** - * Returns true if the list is showing the person details correctly and in correct order. - * @param persons A list of person in the correct order. - */ - public boolean isListMatching(ReadOnlyPerson... persons) { - return this.isListMatching(0, persons); - } - - /** - * Clicks on the ListView. - */ - public void clickOnListView() { - Point2D point= TestUtil.getScreenMidPoint(getListView()); - guiRobot.clickOn(point.getX(), point.getY()); - } - - /** - * Returns true if the {@code persons} appear as the sub list (in that order) at position {@code startPosition}. - */ - public boolean containsInOrder(int startPosition, ReadOnlyPerson... persons) { - List personsInList = getListView().getItems(); - - // Return false if the list in panel is too short to contain the given list - if (startPosition + persons.length > personsInList.size()){ - return false; - } - - // Return false if any of the persons doesn't match - for (int i = 0; i < persons.length; i++) { - if (!personsInList.get(startPosition + i).getName().fullName.equals(persons[i].getName().fullName)){ - return false; - } - } - - return true; - } - - /** - * Returns true if the list is showing the person details correctly and in correct order. - * @param startPosition The starting position of the sub list. - * @param persons A list of person in the correct order. - */ - public boolean isListMatching(int startPosition, ReadOnlyPerson... persons) throws IllegalArgumentException { - if (persons.length + startPosition != getListView().getItems().size()) { - throw new IllegalArgumentException("List size mismatched\n" + - "Expected " + (getListView().getItems().size() - 1) + " persons"); - } - assertTrue(this.containsInOrder(startPosition, persons)); - for (int i = 0; i < persons.length; i++) { - final int scrollTo = i + startPosition; - guiRobot.interact(() -> getListView().scrollTo(scrollTo)); - guiRobot.sleep(200); - if (!TestUtil.compareCardAndPerson(getPersonCardHandle(startPosition + i), persons[i])) { - return false; - } - } - return true; - } - - - public PersonCardHandle navigateToPerson(String name) { - guiRobot.sleep(500); //Allow a bit of time for the list to be updated - final Optional person = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); - if (!person.isPresent()) { - throw new IllegalStateException("Name not found: " + name); - } - - return navigateToPerson(person.get()); - } - - /** - * Navigates the listview to display and select the person. - */ - public PersonCardHandle navigateToPerson(ReadOnlyPerson person) { - int index = getPersonIndex(person); - - guiRobot.interact(() -> { - getListView().scrollTo(index); - guiRobot.sleep(150); - getListView().getSelectionModel().select(index); - }); - guiRobot.sleep(100); - return getPersonCardHandle(person); - } - - - /** - * Returns the position of the person given, {@code NOT_FOUND} if not found in the list. - */ - public int getPersonIndex(ReadOnlyPerson targetPerson) { - List personsInList = getListView().getItems(); - for (int i = 0; i < personsInList.size(); i++) { - if(personsInList.get(i).getName().equals(targetPerson.getName())){ - return i; - } - } - return NOT_FOUND; - } - - /** - * Gets a person from the list by index - */ - public ReadOnlyPerson getPerson(int index) { - return getListView().getItems().get(index); - } - - public PersonCardHandle getPersonCardHandle(int index) { - return getPersonCardHandle(new Person(getListView().getItems().get(index))); - } - - public PersonCardHandle getPersonCardHandle(ReadOnlyPerson person) { - Set nodes = getAllCardNodes(); - Optional personCardNode = nodes.stream() - .filter(n -> new PersonCardHandle(guiRobot, primaryStage, n).isSamePerson(person)) - .findFirst(); - if (personCardNode.isPresent()) { - return new PersonCardHandle(guiRobot, primaryStage, personCardNode.get()); - } else { - return null; - } - } - - protected Set getAllCardNodes() { - return guiRobot.lookup(CARD_PANE_ID).queryAll(); - } - - public int getNumberOfPeople() { - return getListView().getItems().size(); - } -} diff --git a/src/test/java/guitests/guihandles/ResultDisplayHandle.java b/src/test/java/guitests/guihandles/ResultDisplayHandle.java index 110b4682b184..036a171207a2 100644 --- a/src/test/java/guitests/guihandles/ResultDisplayHandle.java +++ b/src/test/java/guitests/guihandles/ResultDisplayHandle.java @@ -3,7 +3,7 @@ import guitests.GuiRobot; import javafx.scene.control.TextArea; import javafx.stage.Stage; -import seedu.address.TestApp; +import seedu.gtd.TestApp; /** * A handler for the ResultDisplay of the UI diff --git a/src/test/java/guitests/guihandles/TaskCardHandle.java b/src/test/java/guitests/guihandles/TaskCardHandle.java new file mode 100644 index 000000000000..190af6855c47 --- /dev/null +++ b/src/test/java/guitests/guihandles/TaskCardHandle.java @@ -0,0 +1,65 @@ +package guitests.guihandles; + +import guitests.GuiRobot; +import javafx.scene.Node; +import javafx.stage.Stage; +import seedu.gtd.model.task.ReadOnlyTask; + +/** + * Provides a handle to a task card in the task list panel. + */ +public class TaskCardHandle extends GuiHandle { + private static final String NAME_FIELD_ID = "#name"; + private static final String DUEDATE_FIELD_ID = "#dueDate"; + private static final String ADDRESS_FIELD_ID = "#address"; + private static final String PRIORITY_FIELD_ID = "#priority"; + + + private Node node; + + public TaskCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ + super(guiRobot, primaryStage, null); + this.node = node; + } + + protected String getTextFromLabel(String fieldId) { + return getTextFromLabel(fieldId, node); + } + + public String getFullName() { + return getTextFromLabel(NAME_FIELD_ID); + } + + public String getDueDate() { + return getTextFromLabel(DUEDATE_FIELD_ID); + } + + public String getAddress() { + return getTextFromLabel(ADDRESS_FIELD_ID); + } + + public String getPriority() { + return getTextFromLabel(PRIORITY_FIELD_ID); + } + + public boolean isSameTask(ReadOnlyTask task) { + return getFullName().equals(task.getName().fullName) && getDueDate().equals(task.getDueDate().value) + && getAddress().equals(task.getAddress().value) + && getPriority().equals(task.getPriority().value); + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof TaskCardHandle) { + TaskCardHandle handle = (TaskCardHandle) obj; + return getFullName().equals(handle.getFullName()) + && getDueDate().equals(handle.getDueDate()); //TODO: compare the rest + } + return super.equals(obj); + } + + @Override + public String toString() { + return getFullName() + " " + getDueDate(); + } +} diff --git a/src/test/java/guitests/guihandles/TaskListPanelHandle.java b/src/test/java/guitests/guihandles/TaskListPanelHandle.java new file mode 100644 index 000000000000..d06cc5ab88e1 --- /dev/null +++ b/src/test/java/guitests/guihandles/TaskListPanelHandle.java @@ -0,0 +1,173 @@ +package guitests.guihandles; + + +import guitests.GuiRobot; +import javafx.geometry.Point2D; +import javafx.scene.Node; +import javafx.scene.control.ListView; +import javafx.stage.Stage; +import seedu.gtd.TestApp; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.testutil.TestUtil; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +/** + * Provides a handle for the panel containing the task list. + */ +public class TaskListPanelHandle extends GuiHandle { + + public static final int NOT_FOUND = -1; + public static final String CARD_PANE_ID = "#cardPane"; + + private static final String TASK_LIST_VIEW_ID = "#taskListView"; + + public TaskListPanelHandle(GuiRobot guiRobot, Stage primaryStage) { + super(guiRobot, primaryStage, TestApp.APP_TITLE); + } + + public List getSelectedTasks() { + ListView taskList = getListView(); + return taskList.getSelectionModel().getSelectedItems(); + } + + public ListView getListView() { + return (ListView) getNode(TASK_LIST_VIEW_ID); + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param tasks A list of task in the correct order. + */ + public boolean isListMatching(ReadOnlyTask... tasks) { + return this.isListMatching(0, tasks); + } + + /** + * Clicks on the ListView. + */ + public void clickOnListView() { + Point2D point= TestUtil.getScreenMidPoint(getListView()); + guiRobot.clickOn(point.getX(), point.getY()); + } + + /** + * Returns true if the {@code tasks} appear as the sub list (in that order) at position {@code startPosition}. + */ + public boolean containsInOrder(int startPosition, ReadOnlyTask... tasks) { + List tasksInList = getListView().getItems(); + + // Return false if the list in panel is too short to contain the given list + if (startPosition + tasks.length > tasksInList.size()){ + return false; + } + + // Return false if any of the tasks doesn't match + for (int i = 0; i < tasks.length; i++) { + if (!tasksInList.get(startPosition + i).getName().fullName.equals(tasks[i].getName().fullName)){ + return false; + } + } + + return true; + } + + /** + * Returns true if the list is showing the task details correctly and in correct order. + * @param startPosition The starting position of the sub list. + * @param tasks A list of task in the correct order. + */ + public boolean isListMatching(int startPosition, ReadOnlyTask... tasks) throws IllegalArgumentException { + if (tasks.length + startPosition != getListView().getItems().size()) { + throw new IllegalArgumentException("List size mismatched\n" + + "Expected " + (getListView().getItems().size() - 1) + " tasks"); + } + assertTrue(this.containsInOrder(startPosition, tasks)); + for (int i = 0; i < tasks.length; i++) { + final int scrollTo = i + startPosition; + guiRobot.interact(() -> getListView().scrollTo(scrollTo)); + guiRobot.sleep(200); + if (!TestUtil.compareCardAndTask(getTaskCardHandle(startPosition + i), tasks[i])) { + System.out.println(startPosition + i); + return false; + } + } + return true; + } + + + public TaskCardHandle navigateToTask(String name) { + guiRobot.sleep(500); //Allow a bit of time for the list to be updated + final Optional task = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); + if (!task.isPresent()) { + throw new IllegalStateException("Name not found: " + name); + } + + return navigateToTask(task.get()); + } + + /** + * Navigates the listview to display and select the task. + */ + public TaskCardHandle navigateToTask(ReadOnlyTask task) { + int index = getTaskIndex(task); + + guiRobot.interact(() -> { + getListView().scrollTo(index); + guiRobot.sleep(150); + getListView().getSelectionModel().select(index); + }); + guiRobot.sleep(100); + return getTaskCardHandle(task); + } + + + /** + * Returns the position of the task given, {@code NOT_FOUND} if not found in the list. + */ + public int getTaskIndex(ReadOnlyTask targetTask) { + List tasksInList = getListView().getItems(); + for (int i = 0; i < tasksInList.size(); i++) { + if(tasksInList.get(i).getName().equals(targetTask.getName())){ + return i; + } + } + return NOT_FOUND; + } + + /** + * Gets a task from the list by index + */ + public ReadOnlyTask getTask(int index) { + return getListView().getItems().get(index); + } + + public TaskCardHandle getTaskCardHandle(int index) { + return getTaskCardHandle(new Task(getListView().getItems().get(index))); + } + + public TaskCardHandle getTaskCardHandle(ReadOnlyTask task) { + Set nodes = getAllCardNodes(); + Optional taskCardNode = nodes.stream() + .filter(n -> new TaskCardHandle(guiRobot, primaryStage, n).isSameTask(task)) + .findFirst(); + if (taskCardNode.isPresent()) { + return new TaskCardHandle(guiRobot, primaryStage, taskCardNode.get()); + } else { + return null; + } + } + + protected Set getAllCardNodes() { + return guiRobot.lookup(CARD_PANE_ID).queryAll(); + } + + public int getNumberOfPeople() { + return getListView().getItems().size(); + } +} \ No newline at end of file diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java deleted file mode 100644 index e1ee0cfb4051..000000000000 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ /dev/null @@ -1,512 +0,0 @@ -package seedu.address.logic; - -import com.google.common.eventbus.Subscribe; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import seedu.address.commons.core.EventsCenter; -import seedu.address.logic.commands.*; -import seedu.address.commons.events.ui.JumpToListRequestEvent; -import seedu.address.commons.events.ui.ShowHelpRequestEvent; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.model.AddressBook; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; -import seedu.address.storage.StorageManager; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static seedu.address.commons.core.Messages.*; - -public class LogicManagerTest { - - /** - * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule - */ - @Rule - public TemporaryFolder saveFolder = new TemporaryFolder(); - - private Model model; - private Logic logic; - - //These are for checking the correctness of the events raised - private ReadOnlyAddressBook latestSavedAddressBook; - private boolean helpShown; - private int targetedJumpIndex; - - @Subscribe - private void handleLocalModelChangedEvent(AddressBookChangedEvent abce) { - latestSavedAddressBook = new AddressBook(abce.data); - } - - @Subscribe - private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) { - helpShown = true; - } - - @Subscribe - private void handleJumpToListRequestEvent(JumpToListRequestEvent je) { - targetedJumpIndex = je.targetIndex; - } - - @Before - public void setup() { - model = new ModelManager(); - String tempAddressBookFile = saveFolder.getRoot().getPath() + "TempAddressBook.xml"; - String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json"; - logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile)); - EventsCenter.getInstance().registerHandler(this); - - latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before. - helpShown = false; - targetedJumpIndex = -1; // non yet - } - - @After - public void teardown() { - EventsCenter.clearSubscribers(); - } - - @Test - public void execute_invalid() throws Exception { - String invalidCommand = " "; - assertCommandBehavior(invalidCommand, - String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); - } - - /** - * Executes the command and confirms that the result message is correct. - * Both the 'address book' and the 'last shown list' are expected to be empty. - * @see #assertCommandBehavior(String, String, ReadOnlyAddressBook, List) - */ - private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { - assertCommandBehavior(inputCommand, expectedMessage, new AddressBook(), Collections.emptyList()); - } - - /** - * Executes the command and confirms that the result message is correct and - * also confirms that the following three parts of the LogicManager object's state are as expected:
- * - the internal address book data are same as those in the {@code expectedAddressBook}
- * - the backing list shown by UI matches the {@code shownList}
- * - {@code expectedAddressBook} was saved to the storage file.
- */ - private void assertCommandBehavior(String inputCommand, String expectedMessage, - ReadOnlyAddressBook expectedAddressBook, - List expectedShownList) throws Exception { - - //Execute the command - CommandResult result = logic.execute(inputCommand); - - //Confirm the ui display elements should contain the right data - assertEquals(expectedMessage, result.feedbackToUser); - assertEquals(expectedShownList, model.getFilteredPersonList()); - - //Confirm the state of data (saved and in-memory) is as expected - assertEquals(expectedAddressBook, model.getAddressBook()); - assertEquals(expectedAddressBook, latestSavedAddressBook); - } - - - @Test - public void execute_unknownCommandWord() throws Exception { - String unknownCommand = "uicfhmowqewca"; - assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND); - } - - @Test - public void execute_help() throws Exception { - assertCommandBehavior("help", HelpCommand.SHOWING_HELP_MESSAGE); - assertTrue(helpShown); - } - - @Test - public void execute_exit() throws Exception { - assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT); - } - - @Test - public void execute_clear() throws Exception { - TestDataHelper helper = new TestDataHelper(); - model.addPerson(helper.generatePerson(1)); - model.addPerson(helper.generatePerson(2)); - model.addPerson(helper.generatePerson(3)); - - assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new AddressBook(), Collections.emptyList()); - } - - - @Test - public void execute_add_invalidArgsFormat() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); - assertCommandBehavior( - "add wrong args wrong args", expectedMessage); - assertCommandBehavior( - "add Valid Name 12345 e/valid@email.butNoPhonePrefix a/valid, address", expectedMessage); - assertCommandBehavior( - "add Valid Name p/12345 valid@email.butNoPrefix a/valid, address", expectedMessage); - assertCommandBehavior( - "add Valid Name p/12345 e/valid@email.butNoAddressPrefix valid, address", expectedMessage); - } - - @Test - public void execute_add_invalidPersonData() throws Exception { - assertCommandBehavior( - "add []\\[;] p/12345 e/valid@e.mail a/valid, address", Name.MESSAGE_NAME_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/not_numbers e/valid@e.mail a/valid, address", Phone.MESSAGE_PHONE_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/12345 e/notAnEmail a/valid, address", Email.MESSAGE_EMAIL_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/12345 e/valid@e.mail a/valid, address t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); - - } - - @Test - public void execute_add_successful() throws Exception { - // setup expectations - TestDataHelper helper = new TestDataHelper(); - Person toBeAdded = helper.adam(); - AddressBook expectedAB = new AddressBook(); - expectedAB.addPerson(toBeAdded); - - // execute command and verify result - assertCommandBehavior(helper.generateAddCommand(toBeAdded), - String.format(AddCommand.MESSAGE_SUCCESS, toBeAdded), - expectedAB, - expectedAB.getPersonList()); - - } - - @Test - public void execute_addDuplicate_notAllowed() throws Exception { - // setup expectations - TestDataHelper helper = new TestDataHelper(); - Person toBeAdded = helper.adam(); - AddressBook expectedAB = new AddressBook(); - expectedAB.addPerson(toBeAdded); - - // setup starting state - model.addPerson(toBeAdded); // person already in internal address book - - // execute command and verify result - assertCommandBehavior( - helper.generateAddCommand(toBeAdded), - AddCommand.MESSAGE_DUPLICATE_PERSON, - expectedAB, - expectedAB.getPersonList()); - - } - - - @Test - public void execute_list_showsAllPersons() throws Exception { - // prepare expectations - TestDataHelper helper = new TestDataHelper(); - AddressBook expectedAB = helper.generateAddressBook(2); - List expectedList = expectedAB.getPersonList(); - - // prepare address book state - helper.addToModel(model, 2); - - assertCommandBehavior("list", - ListCommand.MESSAGE_SUCCESS, - expectedAB, - expectedList); - } - - - /** - * Confirms the 'invalid argument index number behaviour' for the given command - * targeting a single person in the shown list, using visible index. - * @param commandWord to test assuming it targets a single person in the last shown list based on visible index. - */ - private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { - assertCommandBehavior(commandWord , expectedMessage); //index missing - assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned - assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned - assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0 - assertCommandBehavior(commandWord + " not_a_number", expectedMessage); - } - - /** - * Confirms the 'invalid argument index number behaviour' for the given command - * targeting a single person in the shown list, using visible index. - * @param commandWord to test assuming it targets a single person in the last shown list based on visible index. - */ - private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { - String expectedMessage = MESSAGE_INVALID_PERSON_DISPLAYED_INDEX; - TestDataHelper helper = new TestDataHelper(); - List personList = helper.generatePersonList(2); - - // set AB state to 2 persons - model.resetData(new AddressBook()); - for (Person p : personList) { - model.addPerson(p); - } - - assertCommandBehavior(commandWord + " 3", expectedMessage, model.getAddressBook(), personList); - } - - @Test - public void execute_selectInvalidArgsFormat_errorMessageShown() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE); - assertIncorrectIndexFormatBehaviorForCommand("select", expectedMessage); - } - - @Test - public void execute_selectIndexNotFound_errorMessageShown() throws Exception { - assertIndexNotFoundBehaviorForCommand("select"); - } - - @Test - public void execute_select_jumpsToCorrectPerson() throws Exception { - TestDataHelper helper = new TestDataHelper(); - List threePersons = helper.generatePersonList(3); - - AddressBook expectedAB = helper.generateAddressBook(threePersons); - helper.addToModel(model, threePersons); - - assertCommandBehavior("select 2", - String.format(SelectCommand.MESSAGE_SELECT_PERSON_SUCCESS, 2), - expectedAB, - expectedAB.getPersonList()); - assertEquals(1, targetedJumpIndex); - assertEquals(model.getFilteredPersonList().get(1), threePersons.get(1)); - } - - - @Test - public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE); - assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage); - } - - @Test - public void execute_deleteIndexNotFound_errorMessageShown() throws Exception { - assertIndexNotFoundBehaviorForCommand("delete"); - } - - @Test - public void execute_delete_removesCorrectPerson() throws Exception { - TestDataHelper helper = new TestDataHelper(); - List threePersons = helper.generatePersonList(3); - - AddressBook expectedAB = helper.generateAddressBook(threePersons); - expectedAB.removePerson(threePersons.get(1)); - helper.addToModel(model, threePersons); - - assertCommandBehavior("delete 2", - String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS, threePersons.get(1)), - expectedAB, - expectedAB.getPersonList()); - } - - - @Test - public void execute_find_invalidArgsFormat() throws Exception { - String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); - assertCommandBehavior("find ", expectedMessage); - } - - @Test - public void execute_find_onlyMatchesFullWordsInNames() throws Exception { - TestDataHelper helper = new TestDataHelper(); - Person pTarget1 = helper.generatePersonWithName("bla bla KEY bla"); - Person pTarget2 = helper.generatePersonWithName("bla KEY bla bceofeia"); - Person p1 = helper.generatePersonWithName("KE Y"); - Person p2 = helper.generatePersonWithName("KEYKEYKEY sduauo"); - - List fourPersons = helper.generatePersonList(p1, pTarget1, p2, pTarget2); - AddressBook expectedAB = helper.generateAddressBook(fourPersons); - List expectedList = helper.generatePersonList(pTarget1, pTarget2); - helper.addToModel(model, fourPersons); - - assertCommandBehavior("find KEY", - Command.getMessageForPersonListShownSummary(expectedList.size()), - expectedAB, - expectedList); - } - - @Test - public void execute_find_isNotCaseSensitive() throws Exception { - TestDataHelper helper = new TestDataHelper(); - Person p1 = helper.generatePersonWithName("bla bla KEY bla"); - Person p2 = helper.generatePersonWithName("bla KEY bla bceofeia"); - Person p3 = helper.generatePersonWithName("key key"); - Person p4 = helper.generatePersonWithName("KEy sduauo"); - - List fourPersons = helper.generatePersonList(p3, p1, p4, p2); - AddressBook expectedAB = helper.generateAddressBook(fourPersons); - List expectedList = fourPersons; - helper.addToModel(model, fourPersons); - - assertCommandBehavior("find KEY", - Command.getMessageForPersonListShownSummary(expectedList.size()), - expectedAB, - expectedList); - } - - @Test - public void execute_find_matchesIfAnyKeywordPresent() throws Exception { - TestDataHelper helper = new TestDataHelper(); - Person pTarget1 = helper.generatePersonWithName("bla bla KEY bla"); - Person pTarget2 = helper.generatePersonWithName("bla rAnDoM bla bceofeia"); - Person pTarget3 = helper.generatePersonWithName("key key"); - Person p1 = helper.generatePersonWithName("sduauo"); - - List fourPersons = helper.generatePersonList(pTarget1, p1, pTarget2, pTarget3); - AddressBook expectedAB = helper.generateAddressBook(fourPersons); - List expectedList = helper.generatePersonList(pTarget1, pTarget2, pTarget3); - helper.addToModel(model, fourPersons); - - assertCommandBehavior("find key rAnDoM", - Command.getMessageForPersonListShownSummary(expectedList.size()), - expectedAB, - expectedList); - } - - - /** - * A utility class to generate test data. - */ - class TestDataHelper{ - - Person adam() throws Exception { - Name name = new Name("Adam Brown"); - Phone privatePhone = new Phone("111111"); - Email email = new Email("adam@gmail.com"); - Address privateAddress = new Address("111, alpha street"); - Tag tag1 = new Tag("tag1"); - Tag tag2 = new Tag("tag2"); - UniqueTagList tags = new UniqueTagList(tag1, tag2); - return new Person(name, privatePhone, email, privateAddress, tags); - } - - /** - * Generates a valid person using the given seed. - * Running this function with the same parameter values guarantees the returned person will have the same state. - * Each unique seed will generate a unique Person object. - * - * @param seed used to generate the person data field values - */ - Person generatePerson(int seed) throws Exception { - return new Person( - new Name("Person " + seed), - new Phone("" + Math.abs(seed)), - new Email(seed + "@email"), - new Address("House of " + seed), - new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1))) - ); - } - - /** Generates the correct add command based on the person given */ - String generateAddCommand(Person p) { - StringBuffer cmd = new StringBuffer(); - - cmd.append("add "); - - cmd.append(p.getName().toString()); - cmd.append(" p/").append(p.getPhone()); - cmd.append(" e/").append(p.getEmail()); - cmd.append(" a/").append(p.getAddress()); - - UniqueTagList tags = p.getTags(); - for(Tag t: tags){ - cmd.append(" t/").append(t.tagName); - } - - return cmd.toString(); - } - - /** - * Generates an AddressBook with auto-generated persons. - */ - AddressBook generateAddressBook(int numGenerated) throws Exception{ - AddressBook addressBook = new AddressBook(); - addToAddressBook(addressBook, numGenerated); - return addressBook; - } - - /** - * Generates an AddressBook based on the list of Persons given. - */ - AddressBook generateAddressBook(List persons) throws Exception{ - AddressBook addressBook = new AddressBook(); - addToAddressBook(addressBook, persons); - return addressBook; - } - - /** - * Adds auto-generated Person objects to the given AddressBook - * @param addressBook The AddressBook to which the Persons will be added - */ - void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{ - addToAddressBook(addressBook, generatePersonList(numGenerated)); - } - - /** - * Adds the given list of Persons to the given AddressBook - */ - void addToAddressBook(AddressBook addressBook, List personsToAdd) throws Exception{ - for(Person p: personsToAdd){ - addressBook.addPerson(p); - } - } - - /** - * Adds auto-generated Person objects to the given model - * @param model The model to which the Persons will be added - */ - void addToModel(Model model, int numGenerated) throws Exception{ - addToModel(model, generatePersonList(numGenerated)); - } - - /** - * Adds the given list of Persons to the given model - */ - void addToModel(Model model, List personsToAdd) throws Exception{ - for(Person p: personsToAdd){ - model.addPerson(p); - } - } - - /** - * Generates a list of Persons based on the flags. - */ - List generatePersonList(int numGenerated) throws Exception{ - List persons = new ArrayList<>(); - for(int i = 1; i <= numGenerated; i++){ - persons.add(generatePerson(i)); - } - return persons; - } - - List generatePersonList(Person... persons) { - return Arrays.asList(persons); - } - - /** - * Generates a Person object with given name. Other fields will have some dummy values. - */ - Person generatePersonWithName(String name) throws Exception { - return new Person( - new Name(name), - new Phone("1"), - new Email("1@email"), - new Address("House of 1"), - new UniqueTagList(new Tag("tag")) - ); - } - } -} diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java deleted file mode 100644 index 8b02a1668ef6..000000000000 --- a/src/test/java/seedu/address/testutil/PersonBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; -import seedu.address.model.person.*; - -/** - * - */ -public class PersonBuilder { - - private TestPerson person; - - public PersonBuilder() { - this.person = new TestPerson(); - } - - public PersonBuilder withName(String name) throws IllegalValueException { - this.person.setName(new Name(name)); - return this; - } - - public PersonBuilder withTags(String ... tags) throws IllegalValueException { - for (String tag: tags) { - person.getTags().add(new Tag(tag)); - } - return this; - } - - public PersonBuilder withAddress(String address) throws IllegalValueException { - this.person.setAddress(new Address(address)); - return this; - } - - public PersonBuilder withPhone(String phone) throws IllegalValueException { - this.person.setPhone(new Phone(phone)); - return this; - } - - public PersonBuilder withEmail(String email) throws IllegalValueException { - this.person.setEmail(new Email(email)); - return this; - } - - public TestPerson build() { - return this.person; - } - -} diff --git a/src/test/java/seedu/address/testutil/TestPerson.java b/src/test/java/seedu/address/testutil/TestPerson.java deleted file mode 100644 index 19ee5ded1cd3..000000000000 --- a/src/test/java/seedu/address/testutil/TestPerson.java +++ /dev/null @@ -1,76 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.model.tag.UniqueTagList; -import seedu.address.model.person.*; - -/** - * A mutable person object. For testing only. - */ -public class TestPerson implements ReadOnlyPerson { - - private Name name; - private Address address; - private Email email; - private Phone phone; - private UniqueTagList tags; - - public TestPerson() { - tags = new UniqueTagList(); - } - - public void setName(Name name) { - this.name = name; - } - - public void setAddress(Address address) { - this.address = address; - } - - public void setEmail(Email email) { - this.email = email; - } - - public void setPhone(Phone phone) { - this.phone = phone; - } - - @Override - public Name getName() { - return name; - } - - @Override - public Phone getPhone() { - return phone; - } - - @Override - public Email getEmail() { - return email; - } - - @Override - public Address getAddress() { - return address; - } - - @Override - public UniqueTagList getTags() { - return tags; - } - - @Override - public String toString() { - return getAsText(); - } - - public String getAddCommand() { - StringBuilder sb = new StringBuilder(); - sb.append("add " + this.getName().fullName + " "); - sb.append("p/" + this.getPhone().value + " "); - sb.append("e/" + this.getEmail().value + " "); - sb.append("a/" + this.getAddress().value + " "); - this.getTags().getInternalList().stream().forEach(s -> sb.append("t/" + s.tagName + " ")); - return sb.toString(); - } -} diff --git a/src/test/java/seedu/address/testutil/TypicalTestPersons.java b/src/test/java/seedu/address/testutil/TypicalTestPersons.java deleted file mode 100644 index 773f64a98cc3..000000000000 --- a/src/test/java/seedu/address/testutil/TypicalTestPersons.java +++ /dev/null @@ -1,61 +0,0 @@ -package seedu.address.testutil; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.AddressBook; -import seedu.address.model.person.*; - -/** - * - */ -public class TypicalTestPersons { - - public static TestPerson alice, benson, carl, daniel, elle, fiona, george, hoon, ida; - - public TypicalTestPersons() { - try { - alice = new PersonBuilder().withName("Alice Pauline").withAddress("123, Jurong West Ave 6, #08-111") - .withEmail("alice@gmail.com").withPhone("85355255") - .withTags("friends").build(); - benson = new PersonBuilder().withName("Benson Meier").withAddress("311, Clementi Ave 2, #02-25") - .withEmail("johnd@gmail.com").withPhone("98765432") - .withTags("owesMoney", "friends").build(); - carl = new PersonBuilder().withName("Carl Kurz").withPhone("95352563").withEmail("heinz@yahoo.com").withAddress("wall street").build(); - daniel = new PersonBuilder().withName("Daniel Meier").withPhone("87652533").withEmail("cornelia@google.com").withAddress("10th street").build(); - elle = new PersonBuilder().withName("Elle Meyer").withPhone("9482224").withEmail("werner@gmail.com").withAddress("michegan ave").build(); - fiona = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427").withEmail("lydia@gmail.com").withAddress("little tokyo").build(); - george = new PersonBuilder().withName("George Best").withPhone("9482442").withEmail("anna@google.com").withAddress("4th street").build(); - - //Manually added - hoon = new PersonBuilder().withName("Hoon Meier").withPhone("8482424").withEmail("stefan@mail.com").withAddress("little india").build(); - ida = new PersonBuilder().withName("Ida Mueller").withPhone("8482131").withEmail("hans@google.com").withAddress("chicago ave").build(); - } catch (IllegalValueException e) { - e.printStackTrace(); - assert false : "not possible"; - } - } - - public static void loadAddressBookWithSampleData(AddressBook ab) { - - try { - ab.addPerson(new Person(alice)); - ab.addPerson(new Person(benson)); - ab.addPerson(new Person(carl)); - ab.addPerson(new Person(daniel)); - ab.addPerson(new Person(elle)); - ab.addPerson(new Person(fiona)); - ab.addPerson(new Person(george)); - } catch (UniquePersonList.DuplicatePersonException e) { - assert false : "not possible"; - } - } - - public TestPerson[] getTypicalPersons() { - return new TestPerson[]{alice, benson, carl, daniel, elle, fiona, george}; - } - - public AddressBook getTypicalAddressBook(){ - AddressBook ab = new AddressBook(); - loadAddressBookWithSampleData(ab); - return ab; - } -} diff --git a/src/test/java/seedu/address/TestApp.java b/src/test/java/seedu/gtd/TestApp.java similarity index 88% rename from src/test/java/seedu/address/TestApp.java rename to src/test/java/seedu/gtd/TestApp.java index 756642b6c180..5ad86f1fbbf3 100644 --- a/src/test/java/seedu/address/TestApp.java +++ b/src/test/java/seedu/gtd/TestApp.java @@ -1,13 +1,14 @@ -package seedu.address; +package seedu.gtd; import javafx.stage.Screen; import javafx.stage.Stage; -import seedu.address.commons.core.Config; -import seedu.address.commons.core.GuiSettings; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; -import seedu.address.storage.XmlSerializableAddressBook; -import seedu.address.testutil.TestUtil; +import seedu.gtd.MainApp; +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.core.GuiSettings; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.UserPrefs; +import seedu.gtd.storage.XmlSerializableAddressBook; +import seedu.gtd.testutil.TestUtil; import java.util.function.Supplier; diff --git a/src/test/java/seedu/address/commons/core/ConfigTest.java b/src/test/java/seedu/gtd/commons/core/ConfigTest.java similarity index 75% rename from src/test/java/seedu/address/commons/core/ConfigTest.java rename to src/test/java/seedu/gtd/commons/core/ConfigTest.java index 62d58646f736..f02d0ad26fa9 100644 --- a/src/test/java/seedu/address/commons/core/ConfigTest.java +++ b/src/test/java/seedu/gtd/commons/core/ConfigTest.java @@ -1,9 +1,16 @@ -package seedu.address.commons.core; + + + + + +package seedu.gtd.commons.core; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.gtd.commons.core.Config; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -14,11 +21,11 @@ public class ConfigTest { @Test public void toString_defaultObject_stringReturned() { - String defaultConfigAsString = "App title : Address App\n" + + String defaultConfigAsString = "App title : Tary\n" + "Current log level : INFO\n" + "Preference file Location : preferences.json\n" + - "Local data file location : data/addressbook.xml\n" + - "AddressBook name : MyAddressBook"; + "Local data file location : data/tasklist.xml\n" + + "Task List name : MyTaskList"; assertEquals(defaultConfigAsString, new Config().toString()); } diff --git a/src/test/java/seedu/address/commons/core/VersionTest.java b/src/test/java/seedu/gtd/commons/core/VersionTest.java similarity index 98% rename from src/test/java/seedu/address/commons/core/VersionTest.java rename to src/test/java/seedu/gtd/commons/core/VersionTest.java index 87ac01f6c92d..da3a3ed9df38 100644 --- a/src/test/java/seedu/address/commons/core/VersionTest.java +++ b/src/test/java/seedu/gtd/commons/core/VersionTest.java @@ -1,9 +1,11 @@ -package seedu.address.commons.core; +package seedu.gtd.commons.core; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.gtd.commons.core.Version; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/src/test/java/seedu/address/commons/util/AppUtilTest.java b/src/test/java/seedu/gtd/commons/util/AppUtilTest.java similarity index 87% rename from src/test/java/seedu/address/commons/util/AppUtilTest.java rename to src/test/java/seedu/gtd/commons/util/AppUtilTest.java index fbea1d0c1e8e..eb0b71d4e080 100644 --- a/src/test/java/seedu/address/commons/util/AppUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/AppUtilTest.java @@ -1,9 +1,11 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.gtd.commons.util.AppUtil; + import static org.junit.Assert.assertNotNull; public class AppUtilTest { diff --git a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java b/src/test/java/seedu/gtd/commons/util/ConfigUtilTest.java similarity index 95% rename from src/test/java/seedu/address/commons/util/ConfigUtilTest.java rename to src/test/java/seedu/gtd/commons/util/ConfigUtilTest.java index 6699343c4a82..0358794668ed 100644 --- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/ConfigUtilTest.java @@ -1,12 +1,15 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.core.Config; -import seedu.address.commons.exceptions.DataConversionException; + +import seedu.gtd.commons.core.Config; +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.ConfigUtil; +import seedu.gtd.commons.util.FileUtil; import java.io.File; import java.io.IOException; diff --git a/src/test/java/seedu/address/commons/util/FileUtilTest.java b/src/test/java/seedu/gtd/commons/util/FileUtilTest.java similarity index 92% rename from src/test/java/seedu/address/commons/util/FileUtilTest.java rename to src/test/java/seedu/gtd/commons/util/FileUtilTest.java index 8de2621799cf..3aee7d44df3d 100644 --- a/src/test/java/seedu/address/commons/util/FileUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/FileUtilTest.java @@ -1,11 +1,13 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.testutil.SerializableTestClass; -import seedu.address.testutil.TestUtil; + +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.testutil.SerializableTestClass; +import seedu.gtd.testutil.TestUtil; import java.io.File; import java.io.IOException; diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/seedu/gtd/commons/util/JsonUtilTest.java similarity index 85% rename from src/test/java/seedu/address/commons/util/JsonUtilTest.java rename to src/test/java/seedu/gtd/commons/util/JsonUtilTest.java index fc3902188807..20c7427ce602 100644 --- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/JsonUtilTest.java @@ -1,4 +1,4 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; /** * Tests JSON Read and Write diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/gtd/commons/util/StringUtilTest.java similarity index 95% rename from src/test/java/seedu/address/commons/util/StringUtilTest.java rename to src/test/java/seedu/gtd/commons/util/StringUtilTest.java index 194dd71d2c3f..37382b937e9e 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/StringUtilTest.java @@ -1,14 +1,15 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import seedu.gtd.commons.util.StringUtil; + import java.io.FileNotFoundException; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/src/test/java/seedu/address/commons/util/UrlUtilTest.java b/src/test/java/seedu/gtd/commons/util/UrlUtilTest.java similarity index 96% rename from src/test/java/seedu/address/commons/util/UrlUtilTest.java rename to src/test/java/seedu/gtd/commons/util/UrlUtilTest.java index 58efab5fd499..9cc01607b5ff 100644 --- a/src/test/java/seedu/address/commons/util/UrlUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/UrlUtilTest.java @@ -1,7 +1,9 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import org.junit.Test; +import seedu.gtd.commons.util.UrlUtil; + import java.net.MalformedURLException; import java.net.URL; diff --git a/src/test/java/seedu/address/commons/util/XmlUtilTest.java b/src/test/java/seedu/gtd/commons/util/XmlUtilTest.java similarity index 89% rename from src/test/java/seedu/address/commons/util/XmlUtilTest.java rename to src/test/java/seedu/gtd/commons/util/XmlUtilTest.java index dc4fd886c23e..503c3b33e841 100644 --- a/src/test/java/seedu/address/commons/util/XmlUtilTest.java +++ b/src/test/java/seedu/gtd/commons/util/XmlUtilTest.java @@ -1,12 +1,15 @@ -package seedu.address.commons.util; +package seedu.gtd.commons.util; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.model.AddressBook; -import seedu.address.storage.XmlSerializableAddressBook; -import seedu.address.testutil.AddressBookBuilder; -import seedu.address.testutil.TestUtil; + +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.commons.util.XmlUtil; +import seedu.gtd.model.AddressBook; +import seedu.gtd.storage.XmlSerializableAddressBook; +import seedu.gtd.testutil.AddressBookBuilder; +import seedu.gtd.testutil.TestUtil; import javax.xml.bind.JAXBException; import java.io.File; @@ -52,7 +55,7 @@ public void getDataFromFile_emptyFile_DataFormatMismatchException() throws Excep @Test public void getDataFromFile_validFile_validResult() throws Exception { XmlSerializableAddressBook dataFromFile = XmlUtil.getDataFromFile(VALID_FILE, XmlSerializableAddressBook.class); - assertEquals(9, dataFromFile.getPersonList().size()); + assertEquals(9, dataFromFile.getTaskList().size()); assertEquals(0, dataFromFile.getTagList().size()); } @@ -84,7 +87,7 @@ public void saveDataToFile_validFile_dataSaved() throws Exception { //TODO: use equality instead of string comparisons AddressBookBuilder builder = new AddressBookBuilder(new AddressBook()); - dataToWrite = new XmlSerializableAddressBook(builder.withPerson(TestUtil.generateSamplePersonData().get(0)).withTag("Friends").build()); + dataToWrite = new XmlSerializableAddressBook(builder.withTask(TestUtil.generateSampleTaskData().get(0)).withTag("Friends").build()); XmlUtil.saveDataToFile(TEMP_FILE, dataToWrite); dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableAddressBook.class); diff --git a/src/test/java/seedu/gtd/logic/LogicManagerTest.java b/src/test/java/seedu/gtd/logic/LogicManagerTest.java new file mode 100644 index 000000000000..f9a67ef41d87 --- /dev/null +++ b/src/test/java/seedu/gtd/logic/LogicManagerTest.java @@ -0,0 +1,780 @@ +package seedu.gtd.logic; + +import com.google.common.eventbus.Subscribe; + +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.events.model.AddressBookChangedEvent; +import seedu.gtd.commons.events.ui.JumpToListRequestEvent; +import seedu.gtd.commons.events.ui.ShowHelpRequestEvent; +import seedu.gtd.logic.Logic; +import seedu.gtd.logic.LogicManager; +import seedu.gtd.logic.commands.*; +import seedu.gtd.logic.parser.DateNaturalLanguageProcessor; +import seedu.gtd.logic.parser.NaturalLanguageProcessor; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.Model; +import seedu.gtd.model.ModelManager; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.task.*; +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; +import seedu.gtd.storage.StorageManager; +import seedu.gtd.testutil.TaskBuilder; +import seedu.gtd.testutil.TestTask; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static seedu.gtd.commons.core.Messages.*; + +public class LogicManagerTest { + + //@@author addressbook-level4 + + /** + * See https://github.com/junit-team/junit4/wiki/rules#temporaryfolder-rule + */ + @Rule + public TemporaryFolder saveFolder = new TemporaryFolder(); + + private Model model; + private Logic logic; + + //These are for checking the correctness of the events raised + private ReadOnlyAddressBook latestSavedAddressBook; + private boolean helpShown; + private int targetedJumpIndex; + + @Subscribe + private void handleLocalModelChangedEvent(AddressBookChangedEvent abce) { + latestSavedAddressBook = new AddressBook(abce.data); + } + + @Subscribe + private void handleShowHelpRequestEvent(ShowHelpRequestEvent she) { + helpShown = true; + } + + @Subscribe + private void handleJumpToListRequestEvent(JumpToListRequestEvent je) { + targetedJumpIndex = je.targetIndex; + } + + @Before + public void setup() { + model = new ModelManager(); + String tempAddressBookFile = saveFolder.getRoot().getPath() + "TempAddressBook.xml"; + String tempPreferencesFile = saveFolder.getRoot().getPath() + "TempPreferences.json"; + logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile)); + EventsCenter.getInstance().registerHandler(this); + + latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before. + helpShown = false; + targetedJumpIndex = -1; // non yet + } + + @After + public void teardown() { + EventsCenter.clearSubscribers(); + } + + @Test + public void execute_invalid() throws Exception { + String invalidCommand = " "; + assertCommandBehavior(invalidCommand, + String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); + } + + /** + * Executes the command and confirms that the result message is correct. + * Both the 'address book' and the 'last shown list' are expected to be empty. + * @see #assertCommandBehavior(String, String, ReadOnlyAddressBook, List) + */ + private void assertCommandBehavior(String inputCommand, String expectedMessage) throws Exception { + assertCommandBehavior(inputCommand, expectedMessage, new AddressBook(), Collections.emptyList()); + } + + /** + * Executes the command and confirms that the result message is correct and + * also confirms that the following three parts of the LogicManager object's state are as expected:
+ * - the internal address book data are same as those in the {@code expectedAddressBook}
+ * - the backing list shown by UI matches the {@code shownList}
+ * - {@code expectedAddressBook} was saved to the storage file.
+ */ + private void assertCommandBehavior(String inputCommand, String expectedMessage, + ReadOnlyAddressBook expectedAddressBook, + List expectedShownList) throws Exception { + + //Execute the command + CommandResult result = logic.execute(inputCommand); + System.out.println(inputCommand); + + //Confirm the ui display elements should contain the right data + System.out.println(result.feedbackToUser); + System.out.println(expectedMessage); + assertEquals(expectedMessage, result.feedbackToUser); + System.out.println("correct message"); + assertEquals(expectedShownList, model.getFilteredTaskList()); + System.out.println("correct data in UI"); + + //Confirm the state of data (saved and in-memory) is as expected + assertEquals(expectedAddressBook, model.getAddressBook()); + assertEquals(expectedAddressBook, latestSavedAddressBook); + } + + + @Test + public void execute_unknownCommandWord() throws Exception { + String unknownCommand = "uicfhmowqewca"; + assertCommandBehavior(unknownCommand, MESSAGE_UNKNOWN_COMMAND); + } + + //@@author A0146130W-reused + @Test + public void execute_help() throws Exception { + assertCommandBehavior("help", HelpCommand.MESSAGE_USAGE+"/n"+HelpCommand.SHOWING_HELP_MESSAGE); + assertTrue(helpShown); + assertCommandBehavior("help add", AddCommand.MESSAGE_USAGE); + assertCommandBehavior("help select", SelectCommand.MESSAGE_USAGE); + assertCommandBehavior("help delete", DeleteCommand.MESSAGE_USAGE); + assertCommandBehavior("help clear", ClearCommand.MESSAGE_USAGE); + assertCommandBehavior("help find", FindCommand.MESSAGE_USAGE); + assertCommandBehavior("help list", ListCommand.MESSAGE_USAGE); + assertCommandBehavior("help exit", ExitCommand.MESSAGE_USAGE); + } + + //@@author addressbook-level4 + @Test + public void execute_exit() throws Exception { + assertCommandBehavior("exit", ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT); + } + + @Test + public void execute_clear() throws Exception { + TestDataHelper helper = new TestDataHelper(); + model.addTask(helper.generateTask(1)); + model.addTask(helper.generateTask(2)); + model.addTask(helper.generateTask(3)); + + assertCommandBehavior("clear", ClearCommand.MESSAGE_SUCCESS, new AddressBook(), Collections.emptyList()); + } + + @Test + public void execute_add_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); + assertCommandBehavior( + "add ", expectedMessage); + } + + + @Test + public void execute_add_invalidTaskData() throws Exception { + assertCommandBehavior( + "add []\\[;] d/12345 a/valid, address p/1", Name.MESSAGE_NAME_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/not_numbers a/valid, address p/2", DueDate.MESSAGE_DUEDATE_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/12345 a/valid, address p/not_priority_numbers", Priority.MESSAGE_PRIORITY_CONSTRAINTS); + assertCommandBehavior( + "add Valid Name d/12345 a/valid, address p/5 t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); + + } + + //@@author A0130677A + + @Test + public void execute_add_invalidStartEndDate() throws Exception { + assertCommandBehavior( + "add complete tutorial s/tomorrow d/yesterday a/valid, address p/1", START_END_DATE_INVALID_COMMAND_FORMAT); + } + + @Test + public void execute_add_floatingTask() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.floatingTask(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(toBeAdded); + + // execute command and verify result + assertCommandBehavior(helper.generateAddFloatingTask(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, toBeAdded), + expectedAB, + expectedAB.getTaskList()); + } + + @Test + public void execute_add_flexibleTaskData() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.fullTask(); + Task dateChanged = helper.fullTaskChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(dateChanged); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommandInRandomOrder(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, dateChanged), + expectedAB, + expectedAB.getTaskList()); + } + + //@@author addressbook-level4 + + @Test + public void execute_add_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.fullTask(); + Task dateChanged = helper.fullTaskChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(dateChanged); + + // execute command and verify result + assertCommandBehavior(helper.generateAddCommand(toBeAdded), + String.format(AddCommand.MESSAGE_SUCCESS, dateChanged), + expectedAB, + expectedAB.getTaskList()); + + } + + //@@author A0130677A + @Test + public void execute_add_optional_successful() throws Exception { + + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task intendedResult = helper.optionalAddressDateChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(intendedResult); + String optionalAddressCmd = "add clean room d/noon p/3 t/tag1"; + + assertCommandBehavior(optionalAddressCmd, + String.format(AddCommand.MESSAGE_SUCCESS, intendedResult), + expectedAB, + expectedAB.getTaskList()); + } + + //@@author addressbook-level4 + + @Test + public void execute_addDuplicate_notAllowed() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeAdded = helper.fullTask(); + Task changedDate = helper.fullTaskChanged(); + AddressBook expectedAB = new AddressBook(); + expectedAB.addTask(changedDate); + + // setup starting state + model.addTask(changedDate); // task already in internal address book + + // execute command and verify result + assertCommandBehavior( + helper.generateAddCommand(toBeAdded), + AddCommand.MESSAGE_DUPLICATE_TASK, + expectedAB, + expectedAB.getTaskList()); + + } + + /* + @Test + public void execute_edit_successful() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task toBeEdited = helper.adam(); + AddressBook expectedAB = helper.generateAddressBook(2); + expectedAB.editTask(1, toBeEdited); + + // execute command and verify result + assertCommandBehavior(helper.generateEditCommand(toBeEdited), + String.format(EditCommand.MESSAGE_EDIT_TASK_SUCCESS, toBeEdited), + expectedAB, + expectedAB.getTaskList()); + } + */ + + + @Test + public void execute_list_showsAllTasks() throws Exception { + // prepare expectations + TestDataHelper helper = new TestDataHelper(); + AddressBook expectedAB = helper.generateAddressBook(2); + List expectedList = expectedAB.getTaskList(); + + // prepare address book state + helper.addToModel(model, 2); + + assertCommandBehavior("list", + ListCommand.MESSAGE_SUCCESS_LIST, + expectedAB, + expectedList); + } + + //@@author A0130677A + + @Test + public void execute_done_task() throws Exception { + // setup expectations + TestDataHelper helper = new TestDataHelper(); + Task taskDone = helper.fullTaskDone(); + List expectedTasks = helper.generateTaskList(taskDone); + AddressBook expectedAB = helper.generateAddressBook(expectedTasks); + model.addTask(taskDone); + + // execute command and verify result + assertCommandBehavior("done 1", + String.format(DoneCommand.MESSAGE_DONE_TASK_SUCCESS, taskDone), + expectedAB, + expectedAB.getTaskList()); + } + +// @Test +// public void execute_list_done_showsDoneTasks() throws Exception { +// // prepare expectations +// TestDataHelper helper = new TestDataHelper(); +// Task toBeDone = helper.fullTask(); +// Task taskDone = helper.fullTaskDone(); +// List expectedTasks = helper.generateTaskList(taskDone); +// AddressBook expectedAB = helper.generateAddressBook(expectedTasks); +// List expectedList = expectedAB.getTaskList(); +// +// // prepare address book state +// model.addTask(taskDone); +// +// assertCommandBehavior("list done", +// ListCommand.MESSAGE_SUCCESS_LIST_DONE, +// expectedAB, +// expectedList); +// } +// + //@@author generated + + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { + assertCommandBehavior(commandWord , expectedMessage); //index missing + assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned + assertCommandBehavior(commandWord + " 0", expectedMessage); //index cannot be 0 + assertCommandBehavior(commandWord + " not_a_number", expectedMessage); + } + + /** + * Confirms the 'invalid argument index number behaviour' for the given command + * targeting a single task in the shown list, using visible index. + * @param commandWord to test assuming it targets a single task in the last shown list based on visible index. + */ + private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { + String expectedMessage = MESSAGE_INVALID_TASK_DISPLAYED_INDEX; + TestDataHelper helper = new TestDataHelper(); + List taskList = helper.generateTaskList(2); + + // set AB state to 2 tasks + model.clearTaskList(); + for (Task p : taskList) { + model.addTask(p); + } + + assertCommandBehavior(commandWord + " 3", expectedMessage, model.getAddressBook(), taskList); + } + + @Test + public void execute_selectInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("select", expectedMessage); + } + + @Test + public void execute_selectIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("select"); + } + + @Test + public void execute_select_jumpsToCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeTasks = helper.generateTaskList(3); + + AddressBook expectedAB = helper.generateAddressBook(threeTasks); + helper.addToModel(model, threeTasks); + + assertCommandBehavior("select 2", + String.format(SelectCommand.MESSAGE_SELECT_TASK_SUCCESS, 2), + expectedAB, + expectedAB.getTaskList()); + assertEquals(1, targetedJumpIndex); + assertEquals(model.getFilteredTaskList().get(1), threeTasks.get(1)); + } + + + @Test + public void execute_deleteInvalidArgsFormat_errorMessageShown() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE); + assertIncorrectIndexFormatBehaviorForCommand("delete", expectedMessage); + } + + @Test + public void execute_deleteIndexNotFound_errorMessageShown() throws Exception { + assertIndexNotFoundBehaviorForCommand("delete"); + } + + @Test + public void execute_delete_removesCorrectTask() throws Exception { + TestDataHelper helper = new TestDataHelper(); + List threeTasks = helper.generateTaskList(3); + + AddressBook expectedAB = helper.generateAddressBook(threeTasks); + expectedAB.removeTask(threeTasks.get(1)); + helper.addToModel(model, threeTasks); + + assertCommandBehavior("delete 2", + String.format(DeleteCommand.MESSAGE_DELETE_TASK_SUCCESS, threeTasks.get(1)), + expectedAB, + expectedAB.getTaskList()); + } + + + @Test + public void execute_find_invalidArgsFormat() throws Exception { + String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE); + assertCommandBehavior("find ", expectedMessage); + } + + @Test + public void execute_find_onlyMatchesFullWordsInNames() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + Task pTarget2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + Task p1 = helper.generateTaskWithName("KE Y"); + Task p2 = helper.generateTaskWithName("KEYKEYKEY sduauo"); + + List fourTasks = helper.generateTaskList(p1, pTarget1, p2, pTarget2); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = helper.generateTaskList(pTarget1, pTarget2); + helper.addToModel(model, fourTasks); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + @Test + public void execute_find_isNotCaseSensitive() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task p1 = helper.generateTaskWithName("bla bla KEY bla"); + Task p2 = helper.generateTaskWithName("bla KEY bla bceofeia"); + Task p3 = helper.generateTaskWithName("key key"); + Task p4 = helper.generateTaskWithName("KEy sduauo"); + + List fourTasks = helper.generateTaskList(p3, p1, p4, p2); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = fourTasks; + helper.addToModel(model, fourTasks); + + assertCommandBehavior("find KEY", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + @Test + public void execute_find_matchesIfAnyKeywordPresent() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget1 = helper.generateTaskWithName("bla bla KEY bla"); + Task pTarget2 = helper.generateTaskWithName("bla rAnDoM bla bceofeia"); + Task pTarget3 = helper.generateTaskWithName("key key"); + Task p1 = helper.generateTaskWithName("sduauo"); + + List fourTasks = helper.generateTaskList(pTarget1, p1, pTarget2, pTarget3); + AddressBook expectedAB = helper.generateAddressBook(fourTasks); + List expectedList = helper.generateTaskList(pTarget1, pTarget2, pTarget3); + helper.addToModel(model, fourTasks); + + String keywords = "key rAnDoM"; + TestFindHelper findhelper = new TestFindHelper(); + + assertCommandBehavior("find " + keywords, + String.format(findhelper.generateCorrectResultIfExactPhraseNotFound(keywords, expectedList.size())), + expectedAB, + expectedList); + } + + //@@author A0130677A + + @Test + public void execute_find_by_attributes() throws Exception { + TestDataHelper helper = new TestDataHelper(); + Task pTarget = helper.fullTask(); + Task p = helper.floatingTask(); + + List twoTasks = helper.generateTaskList(pTarget, p); + AddressBook expectedAB = helper.generateAddressBook(twoTasks); + List expectedList = helper.generateTaskList(pTarget); + helper.addToModel(model, twoTasks); + + assertCommandBehavior("find p/4", + Command.getMessageForTaskListShownSummary(expectedList.size()), + expectedAB, + expectedList); + } + + + + //@@author generated + + class TestFindHelper{ + + String generateCorrectResultIfExactPhraseNotFound(String keywords, int expectedListSize) { + String task_tasks = (expectedListSize == 1) ? "task" : "tasks"; + String MESSAGE_IF_EXACT_PHRASE_NOT_FOUND = "The exact phrase '" + keywords + "' was not found. Listing " + expectedListSize + " " + task_tasks + " containing the keywords entered instead."; + return MESSAGE_IF_EXACT_PHRASE_NOT_FOUND; + } + } + + //@@author A0130677A + + /** + * A utility class to generate test data. + */ + class TestDataHelper{ + + Task fullTask() throws Exception { + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate("morning"); + DueDate privateDueDate = new DueDate("noon"); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("4"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags); + } + + Task fullTaskChanged() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate(formattedStartDate); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("4"); + boolean isDone = false; + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags, isDone); + } + + Task fullTaskDone() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate(formattedStartDate); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("111, alpha street"); + Priority privatePriority = new Priority("4"); + boolean isDone = true; + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags, isDone); + } + + Task floatingTask() throws Exception { + Name name = new Name("Pick up laundry"); + DueDate startDate = new DueDate("nil"); + DueDate privateDueDate = new DueDate("nil"); + Address address = new Address("nil"); + Priority privatePriority = new Priority("1"); + UniqueTagList tags = new UniqueTagList(); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags); + } + + Task optionalAddressDateChanged() throws Exception { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + Name name = new Name("clean room"); + DueDate startDate = new DueDate(formattedStartDate); + DueDate privateDueDate = new DueDate(formattedDate); + Address address = new Address("none"); + Priority privatePriority = new Priority("3"); + Tag tag1 = new Tag("tag1"); + UniqueTagList tags = new UniqueTagList(tag1); + return new Task(name, startDate, privateDueDate, address, privatePriority, tags); + } + + /** + * Generates a valid task using the given seed. + * Running this function with the same parameter values guarantees the returned task will have the same state. + * Each unique seed will generate a unique Task object. + * + * @param seed used to generate the task data field values + */ + Task generateTask(int seed) throws Exception { + return new Task( + new Name("Task " + seed), + new DueDate("" + Math.abs(seed)), + new DueDate("" + Math.abs(seed)), + new Address(seed + ", -address"), + new Priority("1 "), + new UniqueTagList(new Tag("tag" + Math.abs(seed)), new Tag("tag" + Math.abs(seed + 1))) + ); + } + + /** Generates the correct add command based on the task given */ + String generateAddCommand(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + + cmd.append(p.getName().toString()); + cmd.append(" s/").append(p.getStartDate()); + cmd.append(" d/").append(p.getDueDate()); + cmd.append(" a/").append(p.getAddress()); + cmd.append(" p/").append(p.getPriority()); + + UniqueTagList tags = p.getTags(); + for(Tag t: tags){ + cmd.append(" t/").append(t.tagName); + } + + return cmd.toString(); + } + + String generateAddCommandInRandomOrder(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + + cmd.append(p.getName().toString()); + cmd.append(" p/").append(p.getPriority()); + cmd.append(" a/").append(p.getAddress()); + cmd.append(" s/").append(p.getStartDate()); + cmd.append(" d/").append(p.getDueDate()); + + UniqueTagList tags = p.getTags(); + for(Tag t: tags){ + cmd.append(" t/").append(t.tagName); + } + + return cmd.toString(); + } + + String generateAddFloatingTask(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("add "); + cmd.append(p.getName().toString()); + return cmd.toString(); + } + + //@@author A0146130W + + /** Generates the correct add command based on the task given */ + String generateEditCommand(Task p) { + StringBuffer cmd = new StringBuffer(); + + cmd.append("edit "); + cmd.append(" d/").append(p.getDueDate()); + + return cmd.toString(); + } + //@@author generated + /** + * Generates an AddressBook with auto-generated tasks. + */ + AddressBook generateAddressBook(int numGenerated) throws Exception{ + AddressBook addressBook = new AddressBook(); + addToAddressBook(addressBook, numGenerated); + return addressBook; + } + + /** + * Generates an AddressBook based on the list of Tasks given. + */ + AddressBook generateAddressBook(List tasks) throws Exception{ + AddressBook addressBook = new AddressBook(); + addToAddressBook(addressBook, tasks); + return addressBook; + } + + /** + * Adds auto-generated Task objects to the given AddressBook + * @param addressBook The AddressBook to which the Tasks will be added + */ + void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{ + addToAddressBook(addressBook, generateTaskList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given AddressBook + */ + void addToAddressBook(AddressBook addressBook, List tasksToAdd) throws Exception{ + for(Task p: tasksToAdd){ + addressBook.addTask(p); + } + } + + /** + * Adds auto-generated Task objects to the given model + * @param model The model to which the Tasks will be added + */ + void addToModel(Model model, int numGenerated) throws Exception{ + addToModel(model, generateTaskList(numGenerated)); + } + + /** + * Adds the given list of Tasks to the given model + */ + void addToModel(Model model, List tasksToAdd) throws Exception{ + for(Task p: tasksToAdd){ + model.addTask(p); + } + } + + /** + * Generates a list of Tasks based on the flags. + */ + List generateTaskList(int numGenerated) throws Exception{ + List tasks = new ArrayList<>(); + for(int i = 1; i <= numGenerated; i++){ + tasks.add(generateTask(i)); + } + return tasks; + } + + List generateTaskList(Task... tasks) { + return Arrays.asList(tasks); + } + + /** + * Generates a Task object with given name. Other fields will have some dummy values. + */ + Task generateTaskWithName(String name) throws Exception { + return new Task( + new Name(name), + new DueDate("3"), + new DueDate("1"), + new Address("House of 1"), + new Priority("1"), + new UniqueTagList(new Tag("tag")) + ); + } + } +} diff --git a/src/test/java/seedu/address/model/UnmodifiableObservableListTest.java b/src/test/java/seedu/gtd/model/UnmodifiableObservableListTest.java similarity index 93% rename from src/test/java/seedu/address/model/UnmodifiableObservableListTest.java rename to src/test/java/seedu/gtd/model/UnmodifiableObservableListTest.java index 0334d7e42073..c1e1d2dc2739 100644 --- a/src/test/java/seedu/address/model/UnmodifiableObservableListTest.java +++ b/src/test/java/seedu/gtd/model/UnmodifiableObservableListTest.java @@ -1,16 +1,17 @@ -package seedu.address.model; +package seedu.gtd.model; import javafx.collections.FXCollections; +import seedu.gtd.commons.core.UnmodifiableObservableList; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.commons.core.UnmodifiableObservableList; import java.util.*; import static org.junit.Assert.assertSame; -import static seedu.address.testutil.TestUtil.assertThrows; +import static seedu.gtd.testutil.TestUtil.assertThrows; public class UnmodifiableObservableListTest { diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/gtd/storage/JsonUserPrefsStorageTest.java similarity index 95% rename from src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java rename to src/test/java/seedu/gtd/storage/JsonUserPrefsStorageTest.java index 4e87203611be..2037fd2ffbb9 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/seedu/gtd/storage/JsonUserPrefsStorageTest.java @@ -1,13 +1,15 @@ -package seedu.address.storage; +package seedu.gtd.storage; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.UserPrefs; + +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.model.UserPrefs; +import seedu.gtd.storage.JsonUserPrefsStorage; import java.io.File; import java.io.IOException; diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/gtd/storage/StorageManagerTest.java similarity index 82% rename from src/test/java/seedu/address/storage/StorageManagerTest.java rename to src/test/java/seedu/gtd/storage/StorageManagerTest.java index 6780feab6afc..095b91808eb0 100644 --- a/src/test/java/seedu/address/storage/StorageManagerTest.java +++ b/src/test/java/seedu/gtd/storage/StorageManagerTest.java @@ -1,17 +1,22 @@ -package seedu.address.storage; +package seedu.gtd.storage; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.events.model.AddressBookChangedEvent; -import seedu.address.commons.events.storage.DataSavingExceptionEvent; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.UserPrefs; -import seedu.address.testutil.TypicalTestPersons; -import seedu.address.testutil.EventsCollector; + +import seedu.gtd.commons.events.model.AddressBookChangedEvent; +import seedu.gtd.commons.events.storage.DataSavingExceptionEvent; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.UserPrefs; +import seedu.gtd.storage.JsonUserPrefsStorage; +import seedu.gtd.storage.Storage; +import seedu.gtd.storage.StorageManager; +import seedu.gtd.storage.XmlAddressBookStorage; +import seedu.gtd.testutil.EventsCollector; +import seedu.gtd.testutil.TypicalTestTasks; import java.io.IOException; @@ -55,7 +60,7 @@ public void prefsReadSave() throws Exception { @Test public void addressBookReadSave() throws Exception { - AddressBook original = new TypicalTestPersons().getTypicalAddressBook(); + AddressBook original = new TypicalTestTasks().getTypicalAddressBook(); storageManager.saveAddressBook(original); ReadOnlyAddressBook retrieved = storageManager.readAddressBook().get(); assertEquals(original, new AddressBook(retrieved)); diff --git a/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java b/src/test/java/seedu/gtd/storage/XmlAddressBookStorageTest.java similarity index 85% rename from src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java rename to src/test/java/seedu/gtd/storage/XmlAddressBookStorageTest.java index 04b0db1ce1c7..665db17330e4 100644 --- a/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java +++ b/src/test/java/seedu/gtd/storage/XmlAddressBookStorageTest.java @@ -1,16 +1,18 @@ -package seedu.address.storage; +package seedu.gtd.storage; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; -import seedu.address.testutil.TypicalTestPersons; + +import seedu.gtd.commons.exceptions.DataConversionException; +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.ReadOnlyAddressBook; +import seedu.gtd.model.task.Task; +import seedu.gtd.storage.XmlAddressBookStorage; +import seedu.gtd.testutil.TypicalTestTasks; import java.io.IOException; @@ -61,7 +63,7 @@ public void read_notXmlFormat_exceptionThrown() throws Exception { @Test public void readAndSaveAddressBook_allInOrder_success() throws Exception { String filePath = testFolder.getRoot().getPath() + "TempAddressBook.xml"; - TypicalTestPersons td = new TypicalTestPersons(); + TypicalTestTasks td = new TypicalTestTasks(); AddressBook original = td.getTypicalAddressBook(); XmlAddressBookStorage xmlAddressBookStorage = new XmlAddressBookStorage(filePath); @@ -71,14 +73,14 @@ public void readAndSaveAddressBook_allInOrder_success() throws Exception { assertEquals(original, new AddressBook(readBack)); //Modify data, overwrite exiting file, and read back - original.addPerson(new Person(TypicalTestPersons.hoon)); - original.removePerson(new Person(TypicalTestPersons.alice)); + original.addTask(new Task(TypicalTestTasks.hoon)); + original.removeTask(new Task(TypicalTestTasks.alice)); xmlAddressBookStorage.saveAddressBook(original, filePath); readBack = xmlAddressBookStorage.readAddressBook(filePath).get(); assertEquals(original, new AddressBook(readBack)); //Save and read without specifying file path - original.addPerson(new Person(TypicalTestPersons.ida)); + original.addTask(new Task(TypicalTestTasks.ida)); xmlAddressBookStorage.saveAddressBook(original); //file path not specified readBack = xmlAddressBookStorage.readAddressBook().get(); //file path not specified assertEquals(original, new AddressBook(readBack)); diff --git a/src/test/java/seedu/address/testutil/AddressBookBuilder.java b/src/test/java/seedu/gtd/testutil/AddressBookBuilder.java similarity index 50% rename from src/test/java/seedu/address/testutil/AddressBookBuilder.java rename to src/test/java/seedu/gtd/testutil/AddressBookBuilder.java index a623b81c878f..725b0c4755f2 100644 --- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java +++ b/src/test/java/seedu/gtd/testutil/AddressBookBuilder.java @@ -1,15 +1,15 @@ -package seedu.address.testutil; +package seedu.gtd.testutil; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.tag.Tag; -import seedu.address.model.AddressBook; -import seedu.address.model.person.Person; -import seedu.address.model.person.UniquePersonList; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList; +import seedu.gtd.model.tag.Tag; /** * A utility class to help with building Addressbook objects. * Example usage:
- * {@code AddressBook ab = new AddressBookBuilder().withPerson("John", "Doe").withTag("Friend").build();} + * {@code AddressBook ab = new AddressBookBuilder().withTask("John", "Doe").withTag("Friend").build();} */ public class AddressBookBuilder { @@ -19,8 +19,8 @@ public AddressBookBuilder(AddressBook addressBook){ this.addressBook = addressBook; } - public AddressBookBuilder withPerson(Person person) throws UniquePersonList.DuplicatePersonException { - addressBook.addPerson(person); + public AddressBookBuilder withTask(Task task) throws UniqueTaskList.DuplicateTaskException { + addressBook.addTask(task); return this; } diff --git a/src/test/java/seedu/address/testutil/EventsCollector.java b/src/test/java/seedu/gtd/testutil/EventsCollector.java similarity index 85% rename from src/test/java/seedu/address/testutil/EventsCollector.java rename to src/test/java/seedu/gtd/testutil/EventsCollector.java index c44d6ca6f95a..7301ec559646 100644 --- a/src/test/java/seedu/address/testutil/EventsCollector.java +++ b/src/test/java/seedu/gtd/testutil/EventsCollector.java @@ -1,8 +1,9 @@ -package seedu.address.testutil; +package seedu.gtd.testutil; import com.google.common.eventbus.Subscribe; -import seedu.address.commons.core.EventsCenter; -import seedu.address.commons.events.BaseEvent; + +import seedu.gtd.commons.core.EventsCenter; +import seedu.gtd.commons.events.BaseEvent; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/seedu/address/testutil/SerializableTestClass.java b/src/test/java/seedu/gtd/testutil/SerializableTestClass.java similarity index 98% rename from src/test/java/seedu/address/testutil/SerializableTestClass.java rename to src/test/java/seedu/gtd/testutil/SerializableTestClass.java index ef58ef857179..6a669b87439a 100644 --- a/src/test/java/seedu/address/testutil/SerializableTestClass.java +++ b/src/test/java/seedu/gtd/testutil/SerializableTestClass.java @@ -1,4 +1,4 @@ -package seedu.address.testutil; +package seedu.gtd.testutil; import java.time.LocalDateTime; import java.util.ArrayList; diff --git a/src/test/java/seedu/gtd/testutil/TaskBuilder.java b/src/test/java/seedu/gtd/testutil/TaskBuilder.java new file mode 100644 index 000000000000..a76c6fb1a865 --- /dev/null +++ b/src/test/java/seedu/gtd/testutil/TaskBuilder.java @@ -0,0 +1,55 @@ +package seedu.gtd.testutil; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.model.task.*; +import seedu.gtd.model.tag.Tag; + +/** + * + */ +public class TaskBuilder { + + private TestTask task; + + public TaskBuilder() { + this.task = new TestTask(); + } + + public TaskBuilder withName(String name) throws IllegalValueException { + this.task.setName(new Name(name)); + return this; + } + + public TaskBuilder withTags(String ... tags) throws IllegalValueException { + for (String tag: tags) { + task.getTags().add(new Tag(tag)); + } + return this; + } + + public TaskBuilder withStartDate(String startDate) throws IllegalValueException { + this.task.setStartDate(new DueDate(startDate)); + return this; + } + + public TaskBuilder withDueDate(String dueDate) throws IllegalValueException { + this.task.setDueDate(new DueDate(dueDate)); + return this; + } + + public TaskBuilder withAddress(String address) throws IllegalValueException { + this.task.setAddress(new Address(address)); + return this; + } + + public TaskBuilder withPriority(String priority) throws IllegalValueException { + this.task.setPriority(new Priority(priority)); + return this; + } + + public TestTask build() { + return this.task; + } + +} + diff --git a/src/test/java/seedu/gtd/testutil/TestTask.java b/src/test/java/seedu/gtd/testutil/TestTask.java new file mode 100644 index 000000000000..bd1fa5aead12 --- /dev/null +++ b/src/test/java/seedu/gtd/testutil/TestTask.java @@ -0,0 +1,103 @@ +package seedu.gtd.testutil; + +import seedu.gtd.model.task.*; +import seedu.gtd.model.tag.UniqueTagList; + +/** + * A mutable task object. For testing only. + */ +public class TestTask implements ReadOnlyTask { + + private Name name; + private DueDate startDate; + private DueDate dueDate; + private Address address; + private Priority priority; + private UniqueTagList tags; + private boolean isDone; + + public TestTask() { + tags = new UniqueTagList(); + } + + public TestTask(Name name, DueDate startDate, DueDate dueDate, Address address, Priority priority, UniqueTagList tags) { + this.name = name; + this.startDate = startDate; + this.dueDate = dueDate; + this.address = address; + this.priority = priority; + this.isDone = false; + this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list + } + + public void setName(Name name) { + this.name = name; + } + + public void setDueDate(DueDate dueDate) { + this.dueDate = dueDate; + } + + public void setStartDate(DueDate startDate) { + this.startDate = startDate; + } + + public void setAddress(Address address) { + this.address = address; + } + + public void setPriority(Priority priority) { + this.priority = priority; + } + + @Override + public Name getName() { + return name; + } + + @Override + public DueDate getDueDate() { + return dueDate; + } + + @Override + public DueDate getStartDate() { + return startDate; + } + + @Override + public boolean getisDone() { + return isDone; + } + + @Override + public Address getAddress() { + return address; + } + + @Override + public Priority getPriority() { + return priority; + } + + @Override + public UniqueTagList getTags() { + return tags; + } + + @Override + public String toString() { + return getAsText(); + } + + public String getAddCommand() { + StringBuilder sb = new StringBuilder(); + sb.append("add " + this.getName().fullName + " "); + sb.append("s/" + this.getStartDate().value + " "); + sb.append("d/" + this.getDueDate().value + " "); + sb.append("a/" + this.getAddress().value + " "); + sb.append("p/" + this.getPriority().value + " "); + this.getTags().getInternalList().stream().forEach(s -> sb.append("t/" + s.tagName + " ")); + return sb.toString(); + } +} diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/gtd/testutil/TestUtil.java similarity index 64% rename from src/test/java/seedu/address/testutil/TestUtil.java rename to src/test/java/seedu/gtd/testutil/TestUtil.java index 17c92d66398a..fda93977aa67 100644 --- a/src/test/java/seedu/address/testutil/TestUtil.java +++ b/src/test/java/seedu/gtd/testutil/TestUtil.java @@ -1,26 +1,4 @@ -package seedu.address.testutil; - -import com.google.common.io.Files; -import guitests.guihandles.PersonCardHandle; -import javafx.geometry.Bounds; -import javafx.geometry.Point2D; -import javafx.scene.Node; -import javafx.scene.Scene; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyCodeCombination; -import javafx.scene.input.KeyCombination; -import junit.framework.AssertionFailedError; -import org.loadui.testfx.GuiTest; -import org.testfx.api.FxToolkit; -import seedu.address.TestApp; -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.commons.util.FileUtil; -import seedu.address.commons.util.XmlUtil; -import seedu.address.model.AddressBook; -import seedu.address.model.person.*; -import seedu.address.model.tag.Tag; -import seedu.address.model.tag.UniqueTagList; -import seedu.address.storage.XmlSerializableAddressBook; +package seedu.gtd.testutil; import java.io.File; import java.io.IOException; @@ -33,11 +11,43 @@ import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; +import org.loadui.testfx.GuiTest; +import org.testfx.api.FxToolkit; + +import com.google.common.io.Files; + +import guitests.guihandles.TaskCardHandle; +import javafx.geometry.Bounds; +import javafx.geometry.Point2D; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import junit.framework.AssertionFailedError; +import seedu.gtd.TestApp; +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.commons.util.FileUtil; +import seedu.gtd.commons.util.XmlUtil; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.tag.Tag; +import seedu.gtd.model.tag.UniqueTagList; +import seedu.gtd.model.task.Address; +import seedu.gtd.model.task.DueDate; +import seedu.gtd.model.task.Name; +import seedu.gtd.model.task.Priority; +import seedu.gtd.model.task.ReadOnlyTask; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList; +import seedu.gtd.storage.XmlSerializableAddressBook; + /** * A utility class for test cases. */ public class TestUtil { - + + //@@author addressbook-level4 + public static String LS = System.lineSeparator(); public static void assertThrows(Class expected, Runnable executable) { @@ -60,20 +70,20 @@ public static void assertThrows(Class expected, Runnable ex */ public static String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); - public static final Person[] samplePersonData = getSamplePersonData(); + public static final Task[] sampleTaskData = getSampleTaskData(); - private static Person[] getSamplePersonData() { + private static Task[] getSampleTaskData() { try { - return new Person[]{ - new Person(new Name("Ali Muster"), new Phone("9482424"), new Email("hans@google.com"), new Address("4th street"), new UniqueTagList()), - new Person(new Name("Boris Mueller"), new Phone("87249245"), new Email("ruth@google.com"), new Address("81th street"), new UniqueTagList()), - new Person(new Name("Carl Kurz"), new Phone("95352563"), new Email("heinz@yahoo.com"), new Address("wall street"), new UniqueTagList()), - new Person(new Name("Daniel Meier"), new Phone("87652533"), new Email("cornelia@google.com"), new Address("10th street"), new UniqueTagList()), - new Person(new Name("Elle Meyer"), new Phone("9482224"), new Email("werner@gmail.com"), new Address("michegan ave"), new UniqueTagList()), - new Person(new Name("Fiona Kunz"), new Phone("9482427"), new Email("lydia@gmail.com"), new Address("little tokyo"), new UniqueTagList()), - new Person(new Name("George Best"), new Phone("9482442"), new Email("anna@google.com"), new Address("4th street"), new UniqueTagList()), - new Person(new Name("Hoon Meier"), new Phone("8482424"), new Email("stefan@mail.com"), new Address("little india"), new UniqueTagList()), - new Person(new Name("Ida Mueller"), new Phone("8482131"), new Email("hans@google.com"), new Address("chicago ave"), new UniqueTagList()) + return new Task[]{ + new Task(new Name("Ali Muster"), new DueDate("9482424"), new DueDate("9482424"), new Address("4th street"), new Priority("4"), new UniqueTagList()), + new Task(new Name("Boris Mueller"), new DueDate("9482424"), new DueDate("87249245"), new Address("81th street"), new Priority("3"), new UniqueTagList()), + new Task(new Name("Carl Kurz"), new DueDate("9482424"), new DueDate("95352563"), new Address("wall street"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Daniel Meier"), new DueDate("9482424"), new DueDate("87652533"), new Address("10th street"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Elle Meyer"), new DueDate("9482424"), new DueDate("9482224"), new Address("michegan ave"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Fiona Kunz"), new DueDate("9482424"), new DueDate("9482427"), new Address("little tokyo"), new Priority("1"), new UniqueTagList()), + new Task(new Name("George Best"), new DueDate("9482424"), new DueDate("9482442"), new Address("4th street"), new Priority("4"), new UniqueTagList()), + new Task(new Name("Hoon Meier"), new DueDate("9482424"), new DueDate("8482424"), new Address("little india"), new Priority("1"), new UniqueTagList()), + new Task(new Name("Ida Mueller"), new DueDate("9482424"), new DueDate("8482131"), new Address("chicago ave"), new Priority("1"), new UniqueTagList()) }; } catch (IllegalValueException e) { assert false; @@ -97,8 +107,8 @@ private static Tag[] getSampleTagData() { } } - public static List generateSamplePersonData() { - return Arrays.asList(samplePersonData); + public static List generateSampleTaskData() { + return Arrays.asList(sampleTaskData); } /** @@ -135,7 +145,7 @@ public static void main(String... s) { } public static AddressBook generateEmptyAddressBook() { - return new AddressBook(new UniquePersonList(), new UniqueTagList()); + return new AddressBook(new UniqueTaskList(), new UniqueTagList()); } public static XmlSerializableAddressBook generateSampleStorageAddressBook() { @@ -273,51 +283,75 @@ public static Object getLastElement(List list) { } /** - * Removes a subset from the list of persons. - * @param persons The list of persons - * @param personsToRemove The subset of persons. - * @return The modified persons after removal of the subset from persons. + * Removes a subset from the list of tasks. + * @param tasks The list of tasks + * @param tasksToRemove The subset of tasks. + * @return The modified tasks after removal of the subset from tasks. */ - public static TestPerson[] removePersonsFromList(final TestPerson[] persons, TestPerson... personsToRemove) { - List listOfPersons = asList(persons); - listOfPersons.removeAll(asList(personsToRemove)); - return listOfPersons.toArray(new TestPerson[listOfPersons.size()]); + public static TestTask[] removeTasksFromList(final TestTask[] tasks, TestTask... tasksToRemove) { + List listOfTasks = asList(tasks); + listOfTasks.removeAll(asList(tasksToRemove)); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); } /** - * Returns a copy of the list with the person at specified index removed. + * Returns a copy of the list with the task at specified index removed. * @param list original list to copy from * @param targetIndexInOneIndexedFormat e.g. if the first element to be removed, 1 should be given as index. */ - public static TestPerson[] removePersonFromList(final TestPerson[] list, int targetIndexInOneIndexedFormat) { - return removePersonsFromList(list, list[targetIndexInOneIndexedFormat-1]); + public static TestTask[] removeTaskFromList(final TestTask[] list, int targetIndexInOneIndexedFormat) { + return removeTasksFromList(list, list[targetIndexInOneIndexedFormat-1]); } /** - * Replaces persons[i] with a person. - * @param persons The array of persons. - * @param person The replacement person - * @param index The index of the person to be replaced. + * Replaces tasks[i] with a task. + * @param tasks The array of tasks. + * @param task The replacement task + * @param index The index of the task to be replaced. * @return */ - public static TestPerson[] replacePersonFromList(TestPerson[] persons, TestPerson person, int index) { - persons[index] = person; - return persons; + public static TestTask[] replaceTaskFromList(TestTask[] tasks, TestTask task, int index) { + tasks[index] = task; + return tasks; } /** - * Appends persons to the array of persons. - * @param persons A array of persons. - * @param personsToAdd The persons that are to be appended behind the original array. - * @return The modified array of persons. + * Appends tasks to the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. */ - public static TestPerson[] addPersonsToList(final TestPerson[] persons, TestPerson... personsToAdd) { - List listOfPersons = asList(persons); - listOfPersons.addAll(asList(personsToAdd)); - return listOfPersons.toArray(new TestPerson[listOfPersons.size()]); - } - + public static TestTask[] addTasksToList(final TestTask[] tasks, TestTask... tasksToAdd) { + List listOfTasks = asList(tasks); + listOfTasks.addAll(asList(tasksToAdd)); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + + //@@author A0146130W + + /** + * Edits a task in the array of tasks. + * @param tasks A array of tasks. + * @param tasksToAdd The tasks that are to be appended behind the original array. + * @return The modified array of tasks. + * @throws IllegalValueException + */ + public static TestTask[] editTaskInList(final TestTask[] tasks, int index, String change, TestTask taskToEdit) { + List listOfTasks = asList(tasks); + TestTask taskEditted; + try { + taskEditted = TestUtilParser.editTask(taskToEdit, change); + } catch (IllegalValueException e) { + taskEditted = taskToEdit; + e.printStackTrace(); + } + listOfTasks.set(index-1, taskEditted); + return listOfTasks.toArray(new TestTask[listOfTasks.size()]); + } + + //@@author addressbook-level4 + private static List asList(T[] objs) { List list = new ArrayList<>(); for(T obj : objs) { @@ -326,8 +360,8 @@ private static List asList(T[] objs) { return list; } - public static boolean compareCardAndPerson(PersonCardHandle card, ReadOnlyPerson person) { - return card.isSamePerson(person); + public static boolean compareCardAndTask(TaskCardHandle card, ReadOnlyTask task) { + return card.isSameTask(task); } public static Tag[] getTagList(String tags) { diff --git a/src/test/java/seedu/gtd/testutil/TestUtilParser.java b/src/test/java/seedu/gtd/testutil/TestUtilParser.java new file mode 100644 index 000000000000..8fe7a9677d85 --- /dev/null +++ b/src/test/java/seedu/gtd/testutil/TestUtilParser.java @@ -0,0 +1,43 @@ +//@@author A0146130W + +package seedu.gtd.testutil; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.logic.parser.DateNaturalLanguageProcessor; +import seedu.gtd.logic.parser.NaturalLanguageProcessor; +import seedu.gtd.model.task.Address; +import seedu.gtd.model.task.DueDate; +import seedu.gtd.model.task.Name; +import seedu.gtd.model.task.Priority; + +/** + * A utility class that parses tasks for test cases. + */ +public class TestUtilParser { + + public static TestTask editTask(TestTask task, String change) throws IllegalValueException { + + TestTask newTask = task; + String changeWithoutPrefix = removeDetailPrefix(change); + String changePrefix = change.substring(0, 2); + System.out.println("From TestUtil Parser: " + changePrefix + " " + changeWithoutPrefix); + + switch(change.substring(0, 2)) { + case "d/": newTask = new TestTask(task.getName(), task.getStartDate(), new DueDate(parseDueDate(changeWithoutPrefix)), task.getAddress(), task.getPriority(), task.getTags()); break; + case "a/": newTask = new TestTask(task.getName(), task.getStartDate(), task.getDueDate(), new Address(changeWithoutPrefix), task.getPriority(), task.getTags()); break; + case "p/": newTask = new TestTask(task.getName(), task.getStartDate(), task.getDueDate(), task.getAddress(), new Priority(changeWithoutPrefix), task.getTags()); break; + default: newTask = new TestTask(new Name(change), task.getStartDate(), task.getDueDate(), task.getAddress(), task.getPriority(), task.getTags()); + } + return newTask; + } + + //@@author A0146130W-reused + public static String parseDueDate(String dueDateRaw) { + NaturalLanguageProcessor nlp = new DateNaturalLanguageProcessor(); + return nlp.formatString(dueDateRaw); + } + + private static String removeDetailPrefix(String detailWithPrefix) { + return detailWithPrefix.substring(detailWithPrefix.indexOf('/') + 1); + } +} diff --git a/src/test/java/seedu/gtd/testutil/TypicalTestTasks.java b/src/test/java/seedu/gtd/testutil/TypicalTestTasks.java new file mode 100644 index 000000000000..c864263b8186 --- /dev/null +++ b/src/test/java/seedu/gtd/testutil/TypicalTestTasks.java @@ -0,0 +1,75 @@ +package seedu.gtd.testutil; + +import seedu.gtd.commons.exceptions.IllegalValueException; +import seedu.gtd.logic.parser.DateNaturalLanguageProcessor; +import seedu.gtd.logic.parser.NaturalLanguageProcessor; +import seedu.gtd.model.AddressBook; +import seedu.gtd.model.task.Task; +import seedu.gtd.model.task.UniqueTaskList; +import com.joestelmach.natty.*; + +/** + * + */ +public class TypicalTestTasks { + + public static TestTask alice, aliceChanged, benson, carl, daniel, elle, fiona, george, hoon, hoonChanged, ida, idaChanged; + + public TypicalTestTasks() { + NaturalLanguageProcessor nlpTest = new DateNaturalLanguageProcessor(); + String formattedDate = nlpTest.formatString("noon"); + String formattedStartDate = nlpTest.formatString("morning"); + try { + alice = new TaskBuilder().withName("Alice Pauline").withStartDate("morning").withDueDate("noon").withAddress("123, Jurong West Ave 6, #08-111") + .withPriority("1") + .withTags("friends").build(); + aliceChanged = new TaskBuilder().withName("Alice Pauline").withStartDate(formattedStartDate).withDueDate(formattedDate).withAddress("123, Jurong West Ave 6, #08-111") + .withPriority("1") + .withTags("friends").build(); + benson = new TaskBuilder().withName("Benson Meier").withStartDate("morning").withDueDate("noon").withAddress("311, Clementi Ave 2, #02-25") + .withPriority("2") + .withTags("owesMoney", "friends").build(); + carl = new TaskBuilder().withName("Carl Kurz").withPriority("3").withStartDate("morning").withDueDate("noon").withAddress("wall street").build(); + daniel = new TaskBuilder().withName("Daniel Meier").withPriority("4").withStartDate("morning").withDueDate("noon").withAddress("10th street").build(); + elle = new TaskBuilder().withName("Elle Meyer").withPriority("5").withStartDate("morning").withDueDate("noon").withAddress("michegan ave").build(); + fiona = new TaskBuilder().withName("Fiona Kunz").withPriority("4").withStartDate("morning").withDueDate("noon").withAddress("little tokyo").build(); + george = new TaskBuilder().withName("George Best").withPriority("2").withStartDate("morning").withDueDate("noon").withAddress("4th street").build(); + + //Manually added + hoon = new TaskBuilder().withName("Hoon Meier").withPriority("1").withStartDate("morning").withDueDate("noon").withAddress("little india").build(); + ida = new TaskBuilder().withName("Ida Mueller").withPriority("2").withStartDate("morning").withDueDate("noon").withAddress("chicago ave").build(); + + hoonChanged = new TaskBuilder().withName("Hoon Meier").withPriority("1").withStartDate(formattedStartDate).withDueDate(formattedDate).withAddress("little india").build(); + idaChanged = new TaskBuilder().withName("Ida Mueller").withPriority("2").withStartDate(formattedStartDate).withDueDate(formattedDate).withAddress("chicago ave").build(); + } catch (IllegalValueException e) { + e.printStackTrace(); + assert false : "not possible"; + } + } + + public static void loadAddressBookWithSampleData(AddressBook ab) { + + try { + ab.addTask(new Task(alice)); + ab.addTask(new Task(benson)); + ab.addTask(new Task(carl)); + ab.addTask(new Task(daniel)); + ab.addTask(new Task(elle)); + ab.addTask(new Task(fiona)); + ab.addTask(new Task(george)); + } catch (UniqueTaskList.DuplicateTaskException e) { + assert false : "not possible"; + } + } + + public TestTask[] getTypicalTasks() { + return new TestTask[]{alice, benson, carl, daniel, elle, fiona, george}; + } + + public AddressBook getTypicalAddressBook(){ + AddressBook ab = new AddressBook(); + loadAddressBookWithSampleData(ab); + return ab; + } +} + diff --git a/taryapp.jar b/taryapp.jar new file mode 100644 index 000000000000..c3757f47d8d6 Binary files /dev/null and b/taryapp.jar differ