diff --git a/README.md b/README.md index 13f5c77403f..a1a3c0855a6 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,42 @@ -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) +[![CI Status](https://github.com/AY2021S1-CS2103T-T09-1/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2021S1-CS2103T-T09-1/tp/actions) + +# GradPad + +GradPad is a one-stop solution to **module management** for Computer Science Undergraduates. +Planning for modules has always been a tedious process but it does not have to be. + +The current approach to planning and tracking graduation requirements is to open up tabs after tabs of NUS resources such as +[NUSMods](https://nusmods.com/) and [websites](https://www.comp.nus.edu.sg/programmes/ug/cs/curr/) of the School of + Computing, which can be messy at times. +So, the GradPad team has come up with the idea of an **easy-to-use**, **all-in-one application** that +can ease the process of **module management** for Computer Science Undergraduates. + +GradPad **consolidates** the modules you have taken and **displays** the remaining required modules to +ease your module planning process. A **module searching platform** is also included in GradPad, providing easy +**navigation** of modules. ![Ui](docs/images/Ui.png) -* This is **a sample project for Software Engineering (SE) students**.
- Example usages: - * as a starting point of a course project (as opposed to writing everything from scratch) - * as a case study -* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details. - * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big. - * It comes with a **reasonable level of user and developer documentation**. -* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...). -* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**. -* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info. +## Installation +### Requirements +GradPad requires that you have a Java SE Runtime Environment (JRE) installed on your machine. + +### Steps +1. Download the latest jar release of GradPad from this repository. +2. Run the downloaded jar file + - You can either double-click on the jar file, or + - Execute this command from your terminal: `java -jar GradPad.jar` + +## Usage +For detailed guidance on using GradPad, take a look at our user guide +[here](https://ay2021s1-cs2103t-t09-1.github.io/tp/UserGuide.html). + +For developers, view our detailed documentation +[here](https://ay2021s1-cs2103t-t09-1.github.io/tp/DeveloperGuide.html). + +## Contributing +Although GradPad is an open source project, it is currently not open to public contribution. + +## Authors and acknowledgement +This project is based on the AddressBook-Level3 project created by the +[SE-EDU initiative](https://se-education.org). diff --git a/build.gradle b/build.gradle index be2d2905dde..947980e8ba7 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,11 @@ dependencies { } shadowJar { - archiveName = 'addressbook.jar' + archiveName = 'gradpad.jar' +} + +run { + enableAssertions = true } defaultTasks 'clean', 'test' diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 1c9514e966a..acd6e753b52 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -5,55 +5,46 @@ title: About Us We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg). -You can reach us at the email `seer[at]comp.nus.edu.sg` - ## Project team -### John Doe - - - -[[homepage](http://www.comp.nus.edu.sg/~damithch)] -[[github](https://github.com/johndoe)] -[[portfolio](team/johndoe.md)] - -* Role: Project Advisor +### Lau Siaw Sam -### Jane Doe + - - -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](https://github.com/silvernitro)] +[[portfolio](team/silvernitro.md)] * Role: Team Lead -* Responsibilities: UI +* Responsibilities: Testing -### Johnny Doe +### Lim Shao Kiat - + -[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)] +[[github](http://github.com/shaokiat)] +[[portfolio](team/shaokiat.md)] * Role: Developer -* Responsibilities: Data +* Responsibilities: Documentation -### Jean Doe +### Muhammad Syafiq Bin Abas - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/mhdsyfq)] +[[portfolio](team/mhdsyfq.md)] * Role: Developer -* Responsibilities: Dev Ops + Threading +* Responsibilities: Code Quality -### James Doe +### Soon Xiang, Yan - + -[[github](http://github.com/johndoe)] -[[portfolio](team/johndoe.md)] +[[github](http://github.com/yan-soon)] +[[portfolio](team/yan-soon.md)] * Role: Developer -* Responsibilities: UI +* Responsibilities: Deliverables and deadlines + + diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 4829fe43011..39d2292b41e 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -5,6 +5,27 @@ title: Developer Guide * Table of Contents {:toc} +-------------------------------------------------------------------------------------------------------------------- +## Introduction + +GradPad is an offline computer application meant to help Computer Science students from the +National University of Singapore (NUS) plan their modules with more ease. All module information is +displayed through our simple and organised Graphical User Interface (GUI). GradPad is also optimised +for users who prefer working on a Command Line Interface (CLI). + +The objectives of the application include: + +1. Allowing NUS CS students to track their degree progress. +2. Allowing NUS CS students to plan their modules for upcoming semesters. +3. Providing a fast and convenient way to view NUS CS module details. + +-------------------------------------------------------------------------------------------------------------------- +## About this Guide + +This is a Developer Guide written for developers who wish to contribute to or extend +our GradPad Project. The guide will explain the different components that make up GradPad +and how these components come together to implement GradPad. + -------------------------------------------------------------------------------------------------------------------- ## **Setting up, getting started** @@ -23,24 +44,25 @@ The ***Architecture Diagram*** given above explains the high-level design of the
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams. +:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
-**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for, +**`Main`** has two classes called [`Main`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/src/main/java/seedu/address/MainApp.java). It is responsible for, * At app launch: Initializes the components in the correct sequence, and connects them up with each other. * At shut down: Shuts down the components and invokes cleanup methods where necessary. [**`Commons`**](#common-classes) represents a collection of classes used by multiple other components. -The rest of the App consists of four components. +The rest of the App consists of five components. * [**`UI`**](#ui-component): The UI of the App. * [**`Logic`**](#logic-component): The command executor. * [**`Model`**](#model-component): Holds the data of the App in memory. * [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk. +* [**`Nusmods`**](#nusmods-component): Reads data from the NUSMODS public API. -Each of the four components, +Each of the first four components, * defines its *API* in an `interface` with the same name as the Component. * exposes its functionality using a concrete `{Component Name}Manager` class (which implements the corresponding API `interface` mentioned in the previous point. @@ -62,11 +84,11 @@ The sections below give more details of each component. ![Structure of the UI Component](images/UiClassDiagram.png) **API** : -[`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java) +[`Ui.java`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/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`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `ModuleListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class. -The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) +The `UI` component uses JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/src/main/resources/view/MainWindow.fxml) The `UI` component, @@ -78,11 +100,11 @@ The `UI` component, ![Structure of the Logic Component](images/LogicClassDiagram.png) **API** : -[`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) +[`Logic.java`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/src/main/java/seedu/address/logic/Logic.java) -1. `Logic` uses the `AddressBookParser` class to parse the user command. +1. `Logic` uses the `GradPadParser` class to parse the user command. 1. This results in a `Command` object which is executed by the `LogicManager`. -1. The command execution can affect the `Model` (e.g. adding a person). +1. The command execution can affect the `Model` (e.g. adding a module). 1. The result of the command execution is encapsulated as a `CommandResult` object which is passed back to the `Ui`. 1. In addition, the `CommandResult` object can also instruct the `Ui` to perform certain actions, such as displaying help to the user. @@ -97,31 +119,70 @@ Given below is the Sequence Diagram for interactions within the `Logic` componen ![Structure of the Model Component](images/ModelClassDiagram.png) -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) +**API** : [`Model.java`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/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 an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. +* stores the GradPad data. +* exposes an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. * does not depend on any of the other three components. - -
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique `Tag`, instead of each `Person` needing their own `Tag` object.
-![BetterModelClassDiagram](images/BetterModelClassDiagram.png) - -
- - ### Storage component ![Structure of the Storage Component](images/StorageClassDiagram.png) -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) +**API** : [`Storage.java`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/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 json format and read it back. +* can save the GradPad data in json format and read it back. +* stores required modules that are on the Computer Science curriculum, in the `RequiredCommandStorage` class. +* stores all General Education modules available in NUS, in the `GemCommandStorage` class. + +### Design considerations + +We chose to set up the module-specific Storage classes, with the sole purpose of extracting and parsing the JSON data +so that GradPad can interact with it. + +### Rationale + +This is done so that the `RequiredCommand`, `GemCommand` and `ScienceCommand` classes do not have to worry about +data retrieval and storage, such that they can focus on executing the command logic. + +The two Storage classes are separated to avoid cluttering up `RequiredCommandStorage`, due to the hefty size of +General Education Modules. + +### Nusmods component + +![Structure of the Nusmods Component](images/NusmodsClassDiagram.png) + +**API** : [`NusmodsData.java`](https://github.com/AY2021S1-CS2103T-T09-1/tp/blob/master/src/main/java/seedu/address/nusmods/NusmodsData.java) + +The `Nusmods` component, +* can fetch module data from the NUSMODS public API. +* can save fetched module data in the form of `ModuleInfo` objects to a local JSON file. +* can provide module information based on a module code, in the form of `ModuleInfo` objects. + +Critically, the component is able to fall back on reading pre-fetched module information from a local file when +there's no internet connection. + +#### Design considerations + +We chose to split the `Nusmods` component into two main parts that have the following responsibilities respectively: +* Fetch module data - handled by `DataFetcher` +* Allow other GradPad components to access module data - handled by `NusmodsData` + +##### Rationale + +We chose to do this instead of clumping all the logic together to achieve better encapsulation and abstraction. +With this, the `NusmodsData` class only needs to be concerned with reading available module data, processing it, +and serving it up to the code who requested it. It doesn't need to care about how the data got there. +That's the job of the `DataFetcher` class. As such, it is easy for us to swap out `DataFetcher`, or change its +implementation without the need to touch the public interface provided by `NusmodsData`. This will prove to be +useful when, for example, the NUSMODS API becomes obsolete, and we need to use another API, or if the NUSMODS +API changes, and we need to redesign how we fetch data from it. + ### Common classes @@ -133,41 +194,681 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa This section describes some noteworthy details on how certain features are implemented. +### Nusmods feature +GradPad is tightly integrated with the NUSMods public API by using it to retrieve NUS module information to display +to users. More specifically, GradPad can perform the following operations: + +* Retrieve information about a single module via the `/modules` API endpoint +* Retrieve a list of all NUS modules via the `/moduleList` API endpoint +* Store retrieved module information data from the aforementioned endpoints as local JSON files +* Read pre-fetched module information from local JSON files + +The last 2 operations are crucial to allow GradPad to operate even without an internet connection. This will +be elaborated further below. + +#### How a single module's data is retrieved (when connected to the internet) +GradPad uses the `ModuleInfo` class to represent module information received from NUSMods. Besides storing the various +schema fields in the API's JSON response as plain old Java objects (POJOs), it also handles the massaging of these +fields when they are read. +For e.g. the raw numerical semesters "3" and "4" must be mapped to "Special Term I" and "Special Term II" when read. + +This is the flow of logic when a single module's data is fetched via the API: + +1. Some client code calls the `getModuleInfo` method in the `NusmodsDataManager` class and passes in a +module code as a string parameter. + +2. `getModuleInfo` calls the `fetchModuleInfo` method in the `DataFetcherManager` class. + +3. `fetchModuleInfo` then makes a HTTP GET request to the NUSMods `/modules` endpoint via the `makeGETRequest` +utility method defined within the `HttpUtil` class. It also specifies the module code of the module it wants to fetch. + +4. The `makeGETRequest` method returns the HTTP response as a string. In this case, the response returned is a +JSON string. + +5. `fetchModuleInfo` then parses this JSON string into a `ModuleInfo` object. + +Note: GradPad sets a 3s second timeout for all HTTP GET requests made. Adjust this where necessary. + +The following sequence diagram illustrates this flow: + +![NusmodsFetchModuleSequenceDiagram](images/NusmodsFetchModuleSequenceDiagram.png) + +#### How a single module's data is retrieved (when disconnected from the internet) +Without an internet connection, GradPad clearly cannot retrieve module information via HTTP requests. Instead, +GradPad provides a fallback by including pre-fetched CS curriculum modules in each app release. This is a compromise +we choose to take. While pre-fetched data implies that it might not be up-to-date, we feel that this is better than +completely disallowing users from using GradPad without an internet connection. On top of this, we only choose +to pre-fetch CS curriculum modules as scraping and saving all 5800+ NUS modules means we'll have to make ungraceful +API requests and bloat our releases. It is also not scalable in any way. + +This is the flow of logic when a single module's data is retrieved without an internet collection: + +1. Some client code calls the `getModuleInfo` method in the `NusmodsDataManager` class and passes in a +module code as a string parameter. + +2. `getModuleInfo` calls the `fetchModuleInfo` method in the `DataFetcherManager` class. However, as there is no + internet connection, this method call will fail with an exception. + +3. Catching this, `getModuleInfo` proceeds to call the `getModuleInfoFromFile` method within the same class instead. + +4. `getModuleInfoFromFile` then retrieves the local JSON file containing the module's information, reads it, and +parses it into a `ModuleInfo` object. + +The following sequence diagram illustrates this flow: + +![NusmodsFetchLocalModuleSequenceDiagram](images/NusmodsFetchLocalModuleSequenceDiagram.png) + +#### How module data is scraped and saved locally +As explained in the previous section, GradPad is able to access pre-fetched module information stored as local +JSON files. This section will explain the script used to scrape and save the 100+ CS curriculum modules that runs +before shipping out GradPad releases. + +This is the script's flow of logic: +1. The entry point of this flow is the `fetchAndSaveModules` method within the `DataFetcherManager` class. + +2. `fetchAndSaveModules` starts by fetching a list of all modules from the `/moduleList` API endpoint via a call +to the `fetchModuleSummaryList` method. + +3. `fetchModuleSummaryList` makes the HTTP GET request and parses the JSON string response into a list of + `ModuleSummary` +objects. + +4. This list of `ModuleSummary` objects are then filtered to remove all non-CS curriculum modules by passing it through +the `filterModuleSummaries` method. + +5. Now that this list only contains `ModuleSummary` objects related to the CS curriculum, it is then passed to the +`generateModuleInfoMap` method. + +6. `generateModuleInfoMap`'s main job is to create a map of module codes to `ModuleInfo` objects so that GradPad can +easily retrieve `ModuleInfo` objects given a module code. It does this by +iterating through every `ModuleSummary`, and fetching that module's module information from the `/modules` endpoint. +It then parses each module's information into a `ModuleInfo` object and puts it in a hashmap. + +7. After this map is populated, it is then serialized and saved into a local JSON file. + +Note: GradPad rate-limits step 6 with a 100ms delay between successive hits to the `/modules` endpoint. Adjust where +necessary. + +The following sequence diagram illustrates this flow: + +![NusmodsScrapeModuleSequenceDiagram](images/NusmodsScrapeModuleSequenceDiagram.png) + +### Command Stalling feature + +GradPad stalls certain commands that erase data so that users can provide confirmation as to +whether or not they wish to proceed with the commands. This feature relies heavily on each commands' `requiresStall()` method. + +This is the general flow of logic when handling commands: + +![StalledActivityDiagram](images/StalledActivityDiagram.png) + + +1. If a command `requiresStall`, `LogicManager` will self-invoke its `handleStall()` to store the command to be stalled. + +2. `handleStall()` will then return a `CommandResult` which prompts the user for a confirmation. + +The following sequence diagram illustrates this flow: + +![StalledSequenceDiagram](images/StalledSequenceDiagram.png) + +If the user provides a `YesCommand`, the `stalledCommand` is executed. + +The following sequence diagram illustrates this flow: + +![ConfirmStalledSequenceDiagram](images/ConfirmStalledSequenceDiagram.png) + +However, if the user does not provide a `YesCommand`, the stalledCommand will be set to null, after which an abort message will be displayed. + +The following sequence diagram illustrates this flow: + +![CancelStalledSequenceDiagram](images/CancelStalledSequenceDiagram.png) + +### Add feature +GradPad allows users to add modules to their list. + +The following fields of a module are required (* for optional): +* Module Code +* Tags* + +As with all operations in GradPad, the `AddCommand` class handles the execution of add operations. +The `AddCommandParser` class helps to parse user's input before creating the correct add command. + +Given below is how an add operation behaves at each step of its execution. + +1. The user types in a command string corresponding to an add operation. + +2. This calls the `execute` method of the `LogicManager` class. The user input is passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `gradPadParser` class to parse the string input. + +4. `gradPadParser.parseCommand()` sees that this is an add command, and so uses the `AddCommandParser` class to create a corresponding `AddCommand`, using the `AddCommandParser.parse()` method. + +5. In `AddCommandParser.parse()`, the string input is first split into tokens, i.e. module code, tags, etc. + +6. The `ModuleInfoSearcher.searchModule()` is then called to retrieve module information (module title, modular credits, etc.) from Nusmods. + +7. Once the module information is retrieved, a new `Module` object is created from the module information and tags. It now stores the values that we want to add into our list. + +8. Lastly, in the same method call, an `AddCommand` is created with the new populated `Module`, and is passed back to the `LogicManager` in step 2. + +9. `Logic Manager` executes the newly created `AddCommand`. + +10. Finally, the `Model` is then updated by adding the new `Module` object. + +**Auto-Retrieval of Module Information** + +GradPad's `add` feature supports auto retrieval of module information from NUSMods, mainly a module's title and modular credits. +This is to ensure that the modules added into GradPad are valid NUS modules, and the module information for each module is accurate. + +The following sequence diagram shows how the add command is executed. + +![AddSequenceDiagram](images/AddSequenceDiagram.png) + +### Edit feature +GradPad allows users to edit modules that have already been added. + +The following fields of a module can be edited: +* Module Code +* Tags + +As with all operations in GradPad, the `EditCommand` class handles the execution of edit operations. +The `EditCommandParser` class helps to parse a user's input before creating the correct edit command. + +GradPad uses the `EditModuleDescriptor` class to facilitate edit operations. An `EditModuleDescriptor` is +a temporary bridge that holds the newly-edited fields of a module. You can set the `ModuleCode` and `Tags` of an `EditModuleDescriptor`, +whereas the `ModuleTitle` and `ModularCredits` of a module will be retrieved automatically via NUSMods. +At least one field (`ModuleCode` or `Tags`) must be specified to successfully edit a module. + +Given below is how an edit operation behaves at each step of its execution. + +1. The user types in a command string corresponding to an edit operation. + +2. This calls the `execute` method of the `LogicManager` class. The user input is passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `gradPadParser` class to parse the string input. + +4. `gradPadParser.parseCommand()` sees that this is an edit command, and so uses the `EditCommandParser` +class to create a corresponding `EditCommand`. + +5. In `EditCommandParser`, the string input is first split into tokens, i.e. new module code, new tags, etc. + +6. The `ModuleInfoSearcher.searchModule()` is then called to retrieve module information (module title, modular credits, etc.) of the new module from Nusmods. + +7. Once the module information is retrieved, an `EditModuleDescriptor` object is created from the module information and tags. It now stores +the new values that we want to update the target module with. + +8. An `EditCommand` is then created with this populated `EditModuleDescriptor`, and is passed back to the +`LogicManager` in step 2. + +9. `LogicManager` executes the newly created `EditCommand`. + +10. The target module to be edited is retrieved. A copy of it is made and using the populated + `EditModuleDescriptor`, the fields that are to be updated are replaced with their new values. + +11. The `Model` is then updated by replacing the target module with its new updated copy. + +**Auto-Retrieval of Module Information** + +When a user wishes to edit the module code of a module, GradPad's `edit` feature supports auto retrieval of the new module information from NUSMods, mainly the module's title and modular credits. +This is to ensure that newly edited modules are valid NUS modules, and the module information for the edited module is accurate. + +The following sequence diagram shows how the edit command is executed. + +![EditSequenceDiagram](images/EditSequenceDiagram.png) + +### Delete feature +GradPad allows users to delete modules that have already been added. + +As with all operations in GradPad, the `DeleteCommand` class handles the execution of delete operations. +The `DeleteCommandParser` class helps to parse a user's input before creating the correct delete command. + +Given below is how a delete operation behaves at each step of its execution. + +1. The user types in a command string corresponding to a delete operation. + +2. This calls the `execute` method of the `LogicManager` class. The user input is passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `gradPadParser` class to parse the string input. + +4. `gradPadParser.parseCommand()` sees that this is an delete command, and so uses the `DeleteCommandParser` +class to create a corresponding `DeleteCommand`, using the `DeleteCommandParser.parse()` method. + +5. In `DeleteCommandParser`, the ModuleCode is first extracted from the string input. + +6. A `DeleteCommand` is then created with the ModuleCode, and is passed back to the +`LogicManager` in step 2. + +7. `LogicManager` self-invokes its `handleStall()` method and returns a `CommandResult` which prompts the user for a confirmation. + +8. When the user enters a `YesCommand`, `LogicManager` executes the stalled `DeleteCommand`. + +9. The target module to be deleted is retrieved, if it exists in the Completed Modules of GradPad. + +10. The `Model` is then updated by removing the target module. + +The following sequence diagram shows how the delete command is executed. + +![DeleteSequenceDiagram](images/DeleteSequenceDiagram.png) + +
:information_source: **Note:** If the user performs a Force Delete Operation, +the `LogicManager` will skip the part where it self-invokes its `handleStall()` method, and execute the command immediately. + +
+ +### Find feature +GradPad allows users to find a specific module or a group of modules with common tags or sequence of characters. This feature is especially useful +if there is a long list of modules currently in GradPad and users want to avoid the hassle of scrolling through the +entire list to look for specific module(s). + +As with all operations in GradPad, the `FindCommand` class handles the execution of find operations. +The `FindCommandParser` class helps to parse a user's input before creating the correct find command. + +Given below is a series of steps to show how a find operation behaves during its execution. + +1. The user types in a command string corresponding to a find operation, e.g. "find cs foundation". + +2. This calls the `execute` method of the `LogicManager` class. The user input is passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `GradPadParser` class to parse the string input. + +4. `GradPadParser.parseCommand()` identifies the command as a find command, and thus uses the `FindCommandParser` +class to extract the string input as a list of keywords and create a `CompoundFindPredicate` with said list. + +5. `CompoundFindPredicate` will test every keyword in the list against the logical union of both predicates +`ModuleCodeContainsKeywordsPredicate` and `ModuleContainsTagsPredicate`, and returns the result. + +6. A corresponding `FindCommand` will then be created using this `CompoundFindPredicate`. + +5. This `FindCommand` is then passed back to the`LogicManager` in step 2. + +6. `LogicManager` executes the newly created `FindCommand`. + +7. `FindCommand.execute()` calls for `Model` to filter the GradPad list based on the given predicate(s). + +8. Finally, a `CommandResult` is created and returned to show the result of the execution. + +The following sequence diagram illustrates how the find command is executed. + +![FindSequenceDiagram](images/FindSequenceDiagram.png) + +### List feature + +The `list` command shows all modules that have been added by the user in the `Completed Modules` list. +This is needed as certain commands can change the modules that are being displayed. One such command is the +`find` command, which shows only matching modules in the list. + +Before diving into how the `list` operation is executed, we must first gain a brief understanding of how the +`Completed Modules` list displays its modules, and how this display can be changed by other commands. + +The `Completed Modules` list is implemented by the `ModuleListPanel` UI class. +This class contains a list of modules, which comes from GradPad's `Model` component, that it uses to +display to the user. To change the contents of the list, commands can apply filters to this list through `Model`. +For example, a command may ask `Model` to only show modules that have 4 modular credits. +When this happens, `Completed Modules` naturally changes the modules it displays too. + +The following diagram illustrates this relationship: + +![ModelFilteredListDiagram](images/ModelFilteredListClassDiagram.png) + +With this in mind, the aim of the `list` command is therefore to remove any existing filter on this module list, +effectively getting `Completed Modules` to display all modules once again. + +Given below is a series of steps to show how a list operation behaves during its execution to achieve just this. + +1. The user input is parsed and constructs a `ListCommand` object. (Implementation details of the parser are omitted + here as they are not central in developing an understanding of the `list` operation) + +2. When this command is executed, it calls the `updateFilteredModuleList` method in the `Model` class and passes in +a predicate that lets all modules through the filter. + +3. The `Model` class updates its `filteredModules` list to include all modules as if it were unfiltered. + +4. The `ModuleListPanel` UI component listens to changes in `filteredModules` and updates whenever the list is updated. +It thus updates to display all modules too. + +The following sequence diagram illustrates how the list command is executed. + +![ListSequenceDiagram](images/ListSequenceDiagram.png) + +### CheckMc feature + +The `checkmc` command allows users to view a tally of the total no. of modular credits from the modules present +in the `Completed Modules` list. + +As with all operations in GradPad, the `CheckMcCommand` class handles the execution of `checkmc` operations. +In brief, it works by going through all modules in the `Completed Modules` list and summing up each module's +modular credits. + +Given below is a series of steps to show how a `checkmc` operation behaves during its execution. + +1. The user enters the `checkmc` command string. + +2. This calls the `execute` method of the `LogicManager` class with the user input passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `GradPadParser` class to parse the string input. + +4. `GradPadParser.parseCommand()` identifies the command as a checkmc command and thus creates a `CheckMcCommand` +object. + +5. This command object is then passed back to the `LogicManager` in step 2. + +6. `LogicManager` executes the newly created `CheckMcCommand`. + +7. `CheckMcCommand.execute()` retrieves the `GradPad` object stored within `Model` and accesses the `modules` field +within the `GradPad`. + +8. It then loops through `modules`, which is a list of `Module` objects, and sums up all their modular credits. + +8. Finally, a `CommandResult` is created to show the total no. of modular credits calculated. + +The following sequence diagram illustrates how the `checkmc` command is executed. + +![CheckMcDiagram](images/CheckMcSequenceDiagram.png) + +### Check required modules feature + +The `required` command allows users to view the required modules in the NUS Computer Science curriculum +that they have yet to take. + +When the command is executed, it checks through the current modules in the `Completed Modules` list and ensures +that modules that have already been taken are not displayed in the list of remaining required modules. + +This is achieved with the `RequiredCommand` and `RequiredCommandStorage` class. The `RequiredCommandStorage` class +handles the extracting, parsing of JSON module data while the `RequiredCommand` handles the logic +behind filtering the undone modules. + +As with all operations in GradPad, the `RequiredCommand` class handles the execution of `required` operations. + +Given below is a series of steps to show how a `required` operation behaves during its execution. + +1. The user enters the `required` command string. + +2. This calls the `execute` method of the `LogicManager` class with the user input passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `GradPadParser` class to parse the string input. + +4. `GradPadParser.parseCommand()` identifies the command as a required command and thus creates a `RequiredCommand` +object. + +5. This command object is then passed back to the `LogicManager` in step 2. + +6. `LogicManager` executes the newly created `RequiredCommand`, which will contain the following uninitialised attributes, +list of `currentModules` in GradPad, all the `leftOverModules` and a `RequiredCommandStorage` to store all modules +in the syllabus. + +7. Then, `RequiredCommand.execute()` retrieves the `GradPad` object stored within `Model` and accesses the `modules +` field within the `GradPad` with a few method calls, before storing it in `currentModules`. + +8. `RequiredCommand.execute()` then calls its own method `setStorage` to create a `RequiredCommandStorage` object. + +9. Within the `setStorage` method, various method calls are made for each module category (Eg. Foundation, IT Professionalism) + to set up the `RequiredCommandStorage` object with the all the relevant modules. + +10. Then, `RequireCommand.execute()` call its own method `compareAllGEs()` to check if any GE pillars have not been cleared. +It then keeps track of which pillars have not been cleared. + +11. `RequireCommand.execute()` then proceeds to call its own methods `compareModules`, `compareScience` and `compareInternship` +to keep track of undone modules by cross-referring to the `currentModules` list. + +12. Finally, a `CommandResult` is created with the `leftOverModules` to show the filtered list of remaining required modules. + +The following sequence diagram illustrates how the `required` command is executed. + +![RequiredDiagram](images/RequiredSequenceDiagram.png) + +### Check all available Science Modules + +The `science` command allows users to view all available Science modules available on the Computer Science curriculum. + +When the command is executed, a list of all available Science modules will be displayed on the `Result Display`. + +This is achieved by tapping into the `RequiredCommandStorage` class to extract and parse the Science modules, while the +`ScienceCommand` class handles the logic of displaying the modules. This command is separated from the `required` +command to avoid cluttering of the `Result Display`. + +As with all operations in GradPad, the `ScienceCommand` class handles the execution of `science` operations. + +Given below is a series of steps to show how a `science` operation behaves during its execution. + +1. The user enters the `science` command string. + +2. This calls the `execute` method of the `LogicManager` class with the user input passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `GradPadParser` class to parse the string input. + +4. `GradPadParser.parseCommand()` identifies the command as a science command and thus creates a `ScienceCommand` +object. + +5. This command object is then passed back to the `LogicManager` in step 2. + +6. `LogicManager` executes the newly created `ScienceCommand`, which will contain an empty list of `scienceModules`, +to be filled up by fetching a `RequiredCommandStorage` object. + +7. Then, the `ScienceCommand.execute()` calls its own method, `setScienceModules()` which creates a +`RequiredCommandStorage` object. + +8. Inside the `setScienceModules()` method, the `setRequiredScience` method of the `RequiredCommandStorage` class +is invoked, which sets `scienceModules` with the list of available Science modules. + +9. Then, `ScienceCommand.execute()` calls for `Model` to filter out all existing Science modules in GradPad from +`scienceModules`, via the `hasModule()` method. + +10. Finally, a `CommandResult` is created with the `filteredScienceModules` to display the modules. + +The following sequence diagram illustrates how the `science` command is executed. + +![ScienceDiagram](images/ScienceSequenceDiagram.png) + +### Check all available General Education Modules + +The `gem` command allows users to view all available General Education (GE) modules available in NUS. + +When the command is executed, a list of all available GE modules will be displayed on the `Result Display`. + +This is achieved with the `GemCommand` and `GemCommandStorage` class. The `GemCommandStorage` class +handles the extracting and parsing of JSON module data while the `GemCommand` handles the logic of displaying the +modules. This command is separated from `required` to avoid cluttering up the `Result Display` due to the hefty +amount of GE modules displayed. + +As with all operations in GradPad, the `GemCommand` class handles the execution of `gem` operations. + +Given below is a series of steps to show how a `gem` operation behaves during its execution. + +1. The user enters the `gem` command string. + +2. This calls the `execute` method of the `LogicManager` class with the user input passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `GradPadParser` class to parse the string input. + +4. `GradPadParser.parseCommand()` identifies the command as a gem command and thus creates a `GemCommand` +object. + +5. This command object is then passed back to the `LogicManager` in step 2. + +6. `LogicManager` executes the newly created `GemCommand`, which will contain 2 uninitialised +`GemCommandStorage` attributes, used to store Semester 1 and 2 General Education Modules. + +7. `GemCommand.execute()` then calls its own method `setSem1Storage` and `setSem2Storage` to create 2 `GemCommandStorage` +objects. + +8. Within the `setSem1Storage` and `setSem2Storage` methods, various method calls are made for each GE pillar (Eg. GET, GER) +to set up the `sem1Storage` and `sem2Storage` objects with the all the relevant `sem1GeModules` and `sem2GeModules`. + +9. Then, `GemCommand.execute()` calls for `Model` to filter out all existing GE modules in GradPad from both +`sem1GeModules` and `sem2GeModules`, via the `hasModule()` method. + +10. Finally, a `CommandResult` is created with all the filtered GE modules, displaying all the available +GE modules by Semester. + +The following sequence diagram illustrates how the `gem` command is executed. + +![GemDiagram](images/GemSequenceDiagram.png) + +### Search feature + +The `search` command allows users to search for any module available in NUS and display the module details. + +To retrieve a module's information, the execution of this command interacts with the `Nusmods` component, which +contains all logic related to the access of module data from the NUSMODS public API. We will not go into detail +about the component here as we are mainly focused on the implementation of the search functionality. + +As with all operations in GradPad, the `SearchCommand` class handles the execution of `search` operations. + +Given below is a series of steps to show how a `search` operation behaves during its execution. + +1. The user enters a search command string containing a module code, e.g. "search CS2103T". + +2. This calls the `execute` method of the `LogicManager` class with the user input passed in as a string. + +3. `Logic.execute()` then calls the `parseCommand` method of the `GradPadParser` class to parse the string input. + +4. `GradPadParser.parseCommand()` sees that this is a search command, and so uses the `SearchCommandParser.parse()` +method in `SearchCommandParser`. + +5. In `SearchCommandParser`, `SearchCommandParser.parse()` extracts the ModuleCode from the string input. + +6. A `SearchCommand` is then created with the ModuleCode, and is passed back to the +`LogicManager` in step 2. + +7. `LogicManager` executes the newly created `SearchCommand`. + +8. `SearchCommand.execute()` then creates an instance of `ModuleInfoSearcher` to call the `searchModule()` method by +passing in the module code. + +9. `searchModule()` method will then take in the module code and retrieve the `ModuleInfo` by calling +`NusmodsData.getModuleInfo()` in the `Nusmods` package. + +10. The `ModuleInfo` of the searched module retrieved will then be accessed and formatted according to the display +requirement. + +11. Finally, a `CommandResult` is created to display the module information that has been retrieved. + +The following sequence diagram illustrates how the `search CS2103T` command is executed. + +![SearchSequenceDiagram](images/SearchSequenceDiagram.png) + +### Tags feature + +GradPad allows users to add tags to modules that they add, remove tags from existing modules, list out all +existing tags in GradPad, and filter the `Completed Modules` list by tags. + +Tags are represented by `Tag` objects which are referenced by `Module` objects when modules are tagged. + +To prevent duplicate tags from being created everytime a module is tagged (as was the case in the original AB3), +the `GradPad` class uses a `UniqueTagMap` class to keep track of a collection of unique `Tag` objects. With this, +when a user tags a module with an existing tag, `UniqueTagMap` looks for the existing `Tag` object and adds it to +that `Module` object. As such, all modules who use a particular tag now reference that corresponding singular `Tag +` object. + +The main benefit of this is evident when GradPad needs to print out a list of all tags, which can be simply done +by printing out `UniqueTagMap`'s tags. Otherwise, one would have to iterate through all `Module` objects, +retrieve all their tags, and then filter them to remove any duplicates. + +Following this, `UniqueTagMap` also has to handle the addition and deletion of modules, which is utilized by +the `GradPad` class's add, edit, and delete operations for modules. + +#### Adding a module with tags + +1. When a module with tags is going to be added, the `GradPad` class within the `Model` component is passed that newly + constructed `Module` object from the `Logic` component (see [add feature](#add-feature)). + +2. Its `addModule` method is invoked with this object as a parameter. + +3. Before adding this module to its list of modules, this new module's tags will first be parsed and replaced with +existing tags where possible. This is done using the`checkAndReplaceTags` method in the `UniqueTagMap` class. + +4. The `checkAndReplaceTags` method basically loops through a list of `Tag` objects and checks each one against +the collection of existing `Tag` objects it already holds. If it comes across a "new" `Tag` that already exists +within its collection of tags, it replaces that "new" `Tag` with its existing equivalent `Tag` object in the list. +Otherwise, it adds genuinely new `Tag` objects to its collection. + +5. Now that the new `Module` object's tags have been checked and replaced, the model adds this `Module` to its +`UniqueModuleList`. + +The following diagram illustrates this flow of logic. + +![AddModuleTagsSequenceDiagram](images/AddModuleTagsSequenceDiagram.png) + +#### Deleting a module with tags + +When a module is being deleted, its `Tag` objects within cannot simply be deleted, since multiple +`Module`s may share the same `Tag` object. Yet at the same time, when a `Tag` is no longer referenced by any `Module`, +it should be removed so that it doesn't loiter around in `UniqueTagMap`. To achieve this, `Tag` objects +store a count of the no. of modules that are currently using it. When this count hits 0, the `Tag` can be safely + removed. + +This is the execution flow when a module is deleted: + +1. The `removeModule` method in the `GradPad` class is invoked. + +2. The `remove` method in `UniqueTagMap` is then invoked with a set of all `Tag` objects belonging to the `Module` that +is to be removed. + +3. Within the `remove` method, each `Tag`'s module count is decremented. If the count reaches 0 at this point, +then the `Tag` must be unused by all modules. It is thus removed from the collection of `Tag`s within +`UniqueTagMap`. + +4. The `Module` object can now be deleted from the `UniqueModuleList` in the `GradPad` class. + +The diagram illustrates this flow of logic: + +![DeleteModuleTagsSequenceDiagram](images/DeleteModuleTagsSequenceDiagram.png) + +#### Editing a module's tags + +When editing a module's tags, the old tags are simply "removed" as when +[a module is deleted](#deleting-a-module-with-tags), followed by "adding" the new tags, as when +[a module is added](#adding-a-module-with-tags). + + ### \[Proposed\] Undo/redo feature #### Proposed Implementation -The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations: +The proposed undo/redo mechanism is facilitated by `VersionedGradPad`. It extends `GradPad` with an undo/redo history, +stored internally as a `gradPadStateList` and `currentStatePointer`. Additionally, it implements the +following operations: -* `VersionedAddressBook#commit()` — Saves the current address book state in its history. -* `VersionedAddressBook#undo()` — Restores the previous address book state from its history. -* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history. +* `VersionedGradPad.commit()` — Saves the current GradPad state in its history. +* `VersionedGradPad.undo()` — Restores the previous GradPad state from its history. +* `VersionedGradPad.redo()` — Restores a previously undone GradPad state from its history. -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. +These operations are exposed in the `Model` interface as `Model.commitGradPad()`, `Model.undoGradPad()` +and `Model.redoGradPad()` respectively. Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. -Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state. +Step 1. The user launches the application for the first time. The `VersionedGradPad` will be initialized with +the initial GradPad state, and the `currentStatePointer` pointing to that single GradPad state. ![UndoRedoState0](images/UndoRedoState0.png) -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. +Step 2. The user executes `delete CS2103T` command to delete the `CS2103T` Module from the Completed Modules. The +`delete` command calls `Model.commitGradPad()`, causing the modified state of the GradPad after the `delete CS2103T` +command executes to be saved in the `gradPadStateList`, and the `currentStatePointer` is shifted to the newly inserted +GradPad state. ![UndoRedoState1](images/UndoRedoState1.png) -Step 3. The user executes `add n/David …​` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. +Step 3. The user executes `add CS2100` to add a new module. The `add` command also calls `Model.commitGradPad()`, +causing another modified GradPad state to be saved into the `gradPadStateList`. ![UndoRedoState2](images/UndoRedoState2.png) -
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. +
:information_source: **Note:** If a command fails its execution, it +will not call `Model.commitGradPad()`, so the GradPad state will not be saved into the `gradPadStateList`.
-Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state. +Step 4. The user now decides that adding the module was a mistake, and decides to undo that action by executing the +`undo` command. The `undo` command will call `Model.undoGradPad()`, which will shift the `currentStatePointer` once +to the left, pointing it to the previous GradPad state, and restores the GradPad to that state. ![UndoRedoState3](images/UndoRedoState3.png) -
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather +
:information_source: **Note:** If the `currentStatePointer` is at index +0, pointing to the initial GradPad state, then there are no previous GradPad states to restore. The `undo` command +uses `Model.canUndoGradPad()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
@@ -176,21 +877,31 @@ The following sequence diagram shows how the undo operation works: ![UndoSequenceDiagram](images/UndoSequenceDiagram.png) -
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +
:information_source: **Note:** The lifeline for `UndoCommand` should +end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state. +The `redo` command does the opposite — it calls `Model.redoGradPad()`, which shifts the `currentStatePointer` once +to the right, pointing to the previously undone state, and restores the GradPad to that state. -
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo. +
:information_source: **Note:** If the `currentStatePointer` is at index +`gradPadStateList.size() - 1`, pointing to the latest GradPad state, then there are no undone GradPad states to restore. +The `redo` command uses `Model.canRedoGradPad()` to check if this is the case. If so, it will return an error to the +user rather than attempting to perform the redo.
-Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged. +Step 5. The user then decides to execute the command `list`. Commands that do not modify the GradPad, such as `list`, +will usually not call `Model.commitGradPad()`, `Model.undoGradPad()` or `Model.redoGradPad()`. Thus, the +`gradPadStateList` remains unchanged. ![UndoRedoState4](images/UndoRedoState4.png) -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern desktop applications follow. +Step 6. The user executes `clear`, which calls `Model.commitGradPad()`. Since the `currentStatePointer` is not pointing +at the end of the `gradPadStateList`, all GradPad states after the `currentStatePointer` will be purged. Reason: It no +longer makes sense to redo the `add CS2100` command. This is the behavior that most modern desktop +applications follow. ![UndoRedoState5](images/UndoRedoState5.png) @@ -202,22 +913,15 @@ The following activity diagram summarizes what happens when a user executes a ne ##### Aspect: How undo & redo executes -* **Alternative 1 (current choice):** Saves the entire address book. +* **Alternative 1 (current choice):** Saves the entire GradPad. * Pros: Easy to implement. * Cons: May have performance issues in terms of memory usage. * **Alternative 2:** Individual command knows how to undo/redo by itself. - * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). + * Pros: Will use less memory (e.g. for `delete`, just save the module being deleted). * Cons: We must ensure that the implementation of each individual command are correct. -_{more aspects and alternatives to be added}_ - -### \[Proposed\] Data archiving - -_{Explain here how the data archiving feature will be implemented}_ - - -------------------------------------------------------------------------------------------------------------------- ## **Documentation, logging, testing, configuration, dev-ops** @@ -230,19 +934,20 @@ _{Explain here how the data archiving feature will be implemented}_ -------------------------------------------------------------------------------------------------------------------- -## **Appendix: Requirements** +## **Appendix A: Requirements** ### Product scope **Target user profile**: -* has a need to manage a significant number of contacts -* prefer desktop apps over other types -* can type fast -* prefers typing to mouse interactions -* is reasonably comfortable using CLI apps +Anybody → Students → University Students → tech savvy University student → Computer Science students +NUS Computer Science undergraduate students, who wish to keep track of their necessary modules (how many are done, how many are left), and also the total MCs tabulation. + + +**Value proposition**: + +Keep track of your degree progress and modules taken during your time in NUS with ease. Faster and more lightweight than traditional GUI applications, view and update your progress by issuing simple text commands. Modules are conveniently categorized into their respective groupings e.g. Unrestricted Electives, Computer Science Foundations, etc. -**Value proposition**: manage contacts faster than a typical mouse/GUI driven app ### User stories @@ -251,60 +956,226 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli | Priority | As a …​ | I want to …​ | So that I can…​ | | -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- | -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | user | add a new person | | -| `* * *` | user | delete a person | remove entries that I no longer need | -| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list | -| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident | -| `*` | user with many persons in the address book | sort persons by name | locate a person easily | +| `* * *` | NUS Student | see my total Modular Credits | know how many more I require to graduate | +| `* * *` | NUS Student | see my past Modules | know what I have taken before | +| `* * *` | user | delete modules | remove entries that I no longer need | +| `* * *` | user | add modules and MCs | keep track of my Modular progress | +| `* *` | first-time user | access the available commands | use the app efficiently | +| `* *` | user | save and load my Module data | keep track of my Modular progress | -*{More to be added}* ### Use cases -(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise) +(For all use cases below, the **System** is the `GradPad` and the **Actor** is the `user`, unless specified otherwise) -**Use case: Delete a person** +**Use case: UC01 - Delete a module from `Completed Modules`** **MSS** -1. User requests to list persons -2. AddressBook shows a list of persons -3. User requests to delete a specific person in the list -4. AddressBook deletes the person +1. User requests to delete a specific Module in the `Completed Modules` +2. GradPad deletes the module +3. GradPad displays the deleted module onto the `Result Display` Use case ends. **Extensions** -* 2a. The list is empty. +* 1a. The module does not exist in `Completed Modules`. - Use case ends. + * 1a1. GradPad shows an error message. + + Use case ends. -* 3a. The given index is invalid. +* 2a. The given module code is invalid. - * 3a1. AddressBook shows an error message. + * 2a1. GradPad shows an error message. - Use case resumes at step 2. + Use case resumes at step 1. + +**Use case : UC02 - Add a module into `Completed Modules`** + +**MSS** + +1. User requests to add a module into the `Completed Modules` +2. GradPad adds the module into `Completed Modules` +3. GradPad displays the module added onto the `Result Display` + + Use case ends. + +**Extensions** + +* 1a. The input command format is invalid. + + * 1a1. GradPad shows an error message. + + Use case ends. + +* 1b. Module to be added does not exist in NUS. + + * 1b1. GradPad shows an error message. + + Use case ends. + +**Use case : UC03 - View help** + +**MSS** + +1. User requests to view help commands +2. GradPad shows a list of commands + + Use case ends. + +**Use case : UC04 - View all `Completed Modules`** + +**MSS** + +1. User requests to view list of modules in `Completed Modules` +2. GradPad shows all modules added into `Completed Modules` + + Use case ends. + +**Use case: UC05 - Edit a module in `Completed Modules`** + +1. User requests to edit a module in `Completed Modules` +2. Module is replaced with updated fields +3. GradPad displays the module edited onto the `Result Display` + + Use case ends. + +**Extensions** + +* 1a. The module does not exist in `Completed Modules`. + + * 1a1. GradPad shows an error message. + + Use case ends. + +* 1b. No field is edited for the module. + + * 1b1. GradPad shows an error message. + + Use case ends. + +* 1c. Edited module does not exist in NUS. + + * 1c1. GradPad shows an error message. + + Use case ends. + + +* 1d. The input fields format is invalid. + + * 1d1. GradPad shows an error message. + + Use case ends. + +**Use case : UC06 - Find modules in `Completed Modules`** + +**MSS** + +1. User requests to find modules in `Completed Modules` using keywords. +2. GradPad displays the modules found onto the `Result Display` + + Use case ends. + +**Extensions** + +* 1a. No modules or tag found. + + * 1a1. GradPad displays no modules found message onto `Result Display`. + + Use case ends. + +**Use case : UC07 - View required modules in CS curriculum** + +**MSS** + +1. User requests to view all required modules in CS curriculum +2. GradPad displays the required modules in CS curriculum onto the `Result Display` + + Use case ends. + +**Use case : UC08 - View all available General Education Modules offered in NUS** + +**MSS** + +1. User requests to view all available General Education Modules offered in NUS. +2. GradPad displays all available General Education modules onto the `Result Display` + + Use case ends. + +**Use case : UC09 - View all available Science modules in the CS curriculum** + +**MSS** + +1. User requests to view all available Science modules in the CS curriculum. +2. GradPad displays all available Science modules in the CS curriculum onto the `Result Display` + + Use case ends. + + +**Use case : UC010 - Search for module details** + +**MSS** + +1. User requests to search for a module in NUS. +2. GradPad displays the module details in the `Result Display` + + Use case ends. + +**Extensions** + +* 1a. The module searched does not exist in NUS. + + * 1a1. GradPad shows an error message. + + Use case ends. + +**Use case : UC011 - Check total modular credits** + +**MSS** + +1. User requests to view total modular credits achieved. +2. GradPad displays the total modular credits in the `Result Display` + + Use case ends. + +**Use case : UC12 - exit GradPad** + +**MSS** + +1. User requests to exit GradPad +2. GradPad exits + + Use case ends. -*{More to be added}* ### Non-Functional Requirements 1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +2. Should work on both 32-bit and 64-bit environments. +3. Should be backwards compatible with data produced by earlier versions of the application. +4. Should be able to hold up to 1000 modules without a noticeable sluggishness in performance for typical usage. +5. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. +6. Should be able to respond within one seconds. +7. Should be usable by a novice who has never done module tracking of any sort. +8. The application is not required to handle module tracking by NUS students outside of the Computer Science major. *{More to be added}* ### Glossary * **Mainstream OS**: Windows, Linux, Unix, OS-X -* **Private contact detail**: A contact detail that is not meant to be shared with others +* **Module Code**: Each module of study has a unique module code consisting of a two- or three-letter prefix that generally denotes the discipline, and four digits. + * **First digit**: Represents the level of the module, i.e., 1000 indicates a Level 1 module and 2000, a Level 2 module, etc. + * **Second digit**: Indicates the type of module, i.e., 1 for essential, 2 for elective, 3 for enrichment. +* **Modular Credit (MC)**: A unit of the effort, stated in terms of time, expected of a typical student in managing his/her workload. The MC-value of a module is derived by dividing the estimated total number of workload hours per week for that module by the credit factor of 2.5 (i.e., one MC is equivalent to 2.5 hours of study and preparation per week). + +*{More to be added}* -------------------------------------------------------------------------------------------------------------------- -## **Appendix: Instructions for manual testing** +## **Appendix B: Instructions for Manual Testing** Given below are instructions to test the app manually. @@ -313,44 +1184,392 @@ testers are expected to do more *exploratory* testing.
-### Launch and shutdown - -1. Initial launch +### Launch and Shutdown - 1. Download the jar file and copy into an empty folder +1. Initial Launch - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. + 1. Download the jar file and copy into an empty folder. + + 1. Double-click the jar file.
+ Expected: GUI runs with a set of sample modules. The window size may not be optimum. -1. Saving window preferences +1. Saving Window Preferences 1. Resize the window to an optimum size. Move the window to a different location. Close the window. 1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained. -1. _{ more test cases …​ }_ - -### Deleting a person - -1. Deleting a person while all persons are being shown - - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. - - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. - - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. - - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. - -1. _{ more test cases …​ }_ +1. Shutdown + + 1. Test case: Click the "close" button (red button) at the top of the window.
+ Expected: The window closes immediately. + + 1. Test case: `exit`
+ Expected: GUI shows a farewell message,"Exiting GradPad as requested ..." and delays for 1.5 seconds, + after which the window closes. + + 1. Test case: `exitt`
+ Expected: Window does not close. _Unknown command_ message is shown in the result display. + +### Testing features + +#### Add a Module + +Prerequisites: + 1. Module code must be specified. + 1. Module code format must be valid, e.g. 'CS2100' is a valid module code. + 1. Module to be added must exist in the valid modules list fetched from NUSMods, e.g. module code CS2100 is a + valid module, whereas module code CS1000 is an invalid module. + 1. Module added must not already exist in GradPad. + 1. Command must follow the `add` format. + +Test Cases: +1. Test case: `add cs2100 t/fun`
+ Expected: CS2100 module is added into 'Completed Modules' in GradPad. Details of the added module are shown in the result display. + +1. Test case: `add cs2100`
+ Expected: No module added. _Duplicate module_ message is shown in the result display. + +1. Test case: `add cs2100 t/funnn`
+ Expected: No module added. _Duplicate module_ message is shown in the result display. + +1. Test case: `add cs2100 Computer Organisation`
+ Expected: No module added. _Invalid module code format_ message is shown in the result display. + +1. Test case: `add cs1000`
+ Expected: No module added. _Invalid module_ message is shown in the result display. + +1. Test case: `add`
+ Expected: No module added. _Invalid command format_ message is shown in the result display. + +1. Test case: `addd cs2100`
+ Expected: No module added. _Unknown command_ message is shown in the result display. + +#### Delete a Module + +Prerequisites: + 1. Module code must be specified. + 1. Module code format must be valid. + 1. Module to be deleted must exist in the list being displayed in GradPad, e.g. CS2100 is in the list and CS2106 is not. + 1. Command must follow the `delete` format, followed by `y`, `ye`, or `yes` formats for confirmation. + +Test Cases: +1. Test case: `delete cs2100` followed by `y`
+ Expected: CS2100 module is deleted from 'Completed Modules' in GradPad. _Confirmation_ message followed by + details of the deleted module are shown in the result display. + +1. Test case: `delete cs2100` followed by `n`
+ Expected: No module deleted. _Confirmation_ message followed by _Command aborted_ message are shown in the + result display. + +1. Test case: `delete cs2100 Computer Ogranisation`
+ Expected: No module deleted. _Invalid module code format_ message is shown in the result display. + +1. Test case: `delete cs2106`
+ Expected: No module deleted. _Module not found_ message is shown in the result display. + +1. Test case: `delete`
+ Expected: No module deleted. _Invalid command format_ message is shown in the result display. + +1. Test case: `deleteee cs2100`
+ Expected: No module deleted. _Unknown command_ message is shown in the result display. + +#### Force Delete a module + +Prerequisites: + 1. Module code must be specified. + 1. Module code format must be valid. + 1. Module to be deleted must exist in the list being displayed in GradPad, e.g. CS2100 is in the list and CS2106 is not. + 1. Command must follow the `fdelete` format. + +Test Cases: +1. Test case: `fdelete cs2100`
+ Expected: CS2100 module is deleted from 'Completed Modules' in GradPad. Details of the deleted module are shown + in the result display. + +1. Test case: `fdelete cs2100 Computer Ogranisation`
+ Expected: No module deleted. _Invalid module code format_ message is shown in the result display. + +1. Test case: `fdelete cs2106`
+ Expected: No module deleted. _Module not found_ message is shown in the result display. + +1. Test case: `fdelete`
+ Expected: No module deleted. _Invalid command format_ message is shown in the result display. + +1. Test case: `fdeleteee cs2100`
+ Expected: No module deleted. _Unknown command_ message is shown in the result display. + +#### Clear current list of Modules + +Prerequisites: + 1. Command must follow the `clear` format followed by `y`, `ye`, or `yes` formats for confirmation. + +Test Cases: +1. Test case: `clear` followed by `y`
+ Expected: All modules are cleared from GradPad. _Confirmation_ message followed by _GradPad cleared_ message + are shown in the result display. + +1. Test case: `clearrr` + Expected: Modules are not cleared from GradPad. _Unknown command_ message is shown in the result display. + +#### Force Clear current list of Modules + +Prerequisites: + 1. Command must follow the `fclear` format. + +Test Cases: +1. Test case: `fclear`
+ Expected: All modules are cleared from GradPad. _GradPad cleared_ message is shown in the result display. + +1. Test case: `fclearrr` + Expected: Modules are not cleared from GradPad. _Unknown command_ message is shown in the result display. + +#### Edit a Module + +Prerequisites: + 1. Module code of module to be edited must be specified. + 1. Module code format of module to be edited must be valid. + 1. Module to be edited must exist in the list being displayed in GradPad, e.g. CS2100 is in the list and CS2106 is not. + 1. Module replaced must be an existing module in NUS. + 1. At least 1 field to edit must be specified (module code/tags) + 1. Format of field to edit must be valid. + 1. Replaced fields must be different from current fields. + 1. Command must follow the `edit` format. + +Test Cases: +1. Test case: `edit cs2100 c/cs2103t`
+ Expected: CS2100 module is replaced with CS2103T. Details of the edited module are shown in the result display. + +1. Test case: `edit cs2100 Computer Organisation c/cs2103t`
+ Expected: No module edited. _Invalid module code format_ message is shown in the result display. + +1. Test case: `edit cs2106 c/cs2103t`
+ Expected: No module edited. _Module not found_ message is shown in the result display. + +1. Test case: `edit cs2100 c/cs1000`
+ Expected: No module edited. _Invalid module_ message is shown in the result display. + +1. Test case: `edit cs2100 c/cs2100s Computer Organisation II`
+ Expected: No module edited. _Invalid module code format_ message is shown in the result display. + +1. Test case: `edit cs2100 c/cs2100`
+ Expected: No module edited. _Same module_ message is shown in the result display. + +1. Test case: `edit cs2100 t/fun`
+ Expected: CS2100 module tag is replaced with "fun" tag. Details of the edited module are shown in the result display. + +1. Test case: `edit cs2100 t/fun`
+ Expected: No module edited. _Same tag_ message is shown in the result display. + +1. Test case: `edit cs2100 t/fun!!!`
+ Expected: No module edited. _Invalid tag format_ message is shown in the result display. + +1. Test case: `edit`
+ Expected: No module edited. _Invalid command format_ message is shown in the result display. + +1. Test case: `edittt cs2100 t/cool`
+ Expected: No module edited. _Unknown command_ message is shown in the result display. + +#### List All Modules + +Prerequisite: + 1. Command must follow the `list` format. + +Test Cases: +1. Test case: `list`
+ Expected: The full list of 'Completed Modules' is displayed. "Listed all modules" message shown in the result display. + +1. Test case: `listttt`
+ Expected: Current list remains unchanged. _Unknown command_ message is shown in the result display. + +#### Find a Specific Module or a Group of Modules + +Prerequisites: + 1. Arguments must be specified. + 1. Module to be included must exist in the 'Completed Modules' in GradPad, e.g. CS2100 (fun), CS2101 (fun), + ST2334 (fun) and CS3230 are in the list and CS2106 is not. The words in the bracket represent the module tags. + 1. Command must follow the `find` format. + +Test Cases: +1. Test case: `find cs2`
+ Expected: CS2100 and CS2101 are displayed. "2 modules found!" message shown in the result display. + +1. Test case: `find cs2 st`
+ Expected: CS2100, CS2101 and ST2334 are displayed. "3 modules found!" message shown in the result display. + +1. Test case: `find cs3230`
+ Expected: CS3230 is displayed. "1 modules found!" message shown in the result display. + +1. Test case: `find cs2106`
+ Expected: No modules displayed. "0 modules found!" message shown in the result display. + +1. Test case: `find fu`
+ Expected: CS2100, CS2101 and ST2334 are displayed. "3 modules found!" message shown in the result display. + +1. Test case: `find fun`
+ Expected: CS2100, CS2101 and ST2334 are displayed. "3 modules found!" message shown in the result display. + +1. Test case: `find funnnn`
+ Expected: No modules displayed. "0 modules found!" message shown in the result display. + +1. Test case: `find`
+ Expected: Current list is unchanged. _Invalid command format_ message is shown in the result display. + +1. Test case: `findd CS2101`
+ Expected: No modules displayed. _Unknown command_ message is shown in the result display. + +#### Check Total Modular Credits + +Prerequisite: + 1. Command must follow the `checkmc` format. + +Test Cases: +1. Test case: `checkmc`
+ Expected: Total modular credits are calculated and displayed. If there are no modules in 'Completed Modules', + total modular credits will be 0. + +1. Test case: `checkmccccc`
+ Expected: Total modular credits are not calculated. _Unknown command_ message is shown in the result display. + +#### Open Help Page + +Prerequisite: + 1. Command must follow the `help` format. + +Test Cases: +1. Test case: `help`
+ Expected: Help page is displayed. + +1. Test case: `helppppp`
+ Expected: Help page is not displayed. _Unknown command_ message is shown in the result display. + +#### Show Required Modules + +Prerequisite: + 1. Command must follow the `required` format. + +Test Cases: +1. Test case: `required`
+ Expected: All required modules are displayed in the result display. Modules already in the 'Completed Modules' list in GradPad would not be displayed in the 'Required Modules' list. + +1. Test case: `requiredddd`
+ Expected: Required modules are not displayed. _Unknown command_ message is shown in the result display. + +#### Show available Science Modules + +Prerequisite: + 1. Command must follow the `science` format. + +Test Cases: +1. Test case: `science`
+ Expected: All available Science modules are displayed in the result display. Modules already in the 'Completed Modules' + list would not be displayed. + +1. Test case: `scienceeeee`
+ Expected: Science modules are not displayed. _Unknown command_ message is shown in the result display. + +#### Show available General Education Modules + +Prerequisite: + 1. Command must follow the `gem` format. + +Test Cases: +1. Test case: `gem`
+ Expected: All available General Education modules are displayed in the result display. Modules already in the 'Completed Modules' + list would not be displayed. + +1. Test case: `gemmmmm`
+ Expected: General Education modules are not displayed. _Unknown command_ message is shown in the result display. + +#### Search Module Information + +Prerequisites: + 1. Module code must be specified. + 1. Module code format must be valid. + 1. Module to be searched must exist in the valid modules list fetched from NUSMods,e.g. module code CS2100 + is a valid module, whereas module code CS1000 is an invalid module. + 1. Command must follow the `search` format. + +Test Cases: +1. Test case: `search cs2100`
+ Expected: CS2100 module information is displayed in the result display. + +1. Test case: `search cs2100 Computer Organisation`
+ Expected: No module information is displayed. _Invalid module code format_ message is shown in the result display. + +1. Test case: `search cs1000`
+ Expected: No module information is displayed. _Invalid module_ message is shown in the result display. + +1. Test case: `search`
+ Expected: No module information is displayed. _Invalid command format_ message is shown in the result display. + +1. Other invalid search commands to try: `search c/cs2103t`, `search 1`
+ Expected: No module information is displayed. _Invalid module_ message is shown in the result display. +1. Test case: `searchh cs2100`
+ Expected: No module information is displayed. _Unknown command_ message is shown in the result display. + +#### List all current Tags + +Prerequisites: + 1. Command must follow the `tags` format. + +Test Cases: +1. Test case: `tags`
+ Expected: All tags currently in use will be shown in the result display. + +1. Test case: `tagss`
+ Expected: No tags displayed. _Unknown command_ message is shown in the result display. ### Saving data 1. Dealing with missing/corrupted data files - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ - -1. _{ more test cases …​ }_ + 1. Corrupt the current saved data file under `./data/gradpad.json`. One way is to add `-` into one of the module + code. + + 1. Open the jar file `gradpad.jar`
+ Expected: No data shown in the Completed Modules list. + + 1. Delete the data folder `./data` + + 1. Open the jar file `gradpad.jar`
+ Expected: Saved data will reset to sample data and will be shown in the Completed Modules list. + +## **Appendix C: Effort** + +### 1. NusMods ![NUSMods](images/nusmods_small.png)
+GradPad is tightly integrated with the NUSMods public API by using it to retrieve NUS module information to display to +users. This integration with NUSMods is definitely complex and not easy. Fortunately, one of our team members had some +experience with web development and managed to integrate the API into GradPad. This allows GradPad to +retrieve up-to-date module data directly from NUSMods, making GradPad more relevant and adaptable. + +As if integrating GradPad, a Java application, with a public web API isn't tedious enough, we also had to meet the +project constraint that GradPad should be able to function even without an active connection to the API. Ideally, +it would be straightforward for us to simply scrape data from the API and store it in our own database via a DBMS, +which is generally done in other applications to reduce dependency on external APIs. However, the module also +forbids the use of a DBMS, which meant we had to come up with a way to scrape and store data in local files instead. +At the end of the day, we spent a considerable effort to write a script in Java that scrapes data from the API +, transforms them into Java objects, and serializes them into human-readable JSON files. + +### 2. NUS CS Curriculum +Our target audience is Computer Science Undergraduates and so we had to get the NUS CS curriculum and utilize +this data in GradPad. Our initial idea was to just store the entire list of modules in the CS curriculum into GradPad. +However, we soon realized that there are way more modules than we had anticipated as there is a list of GEMs and +science modules that we had initially missed out. Besides this, there are also preclusions in some modules and +equivalent modules with different module codes. These are tough challenges that we had to brainstorm hard to come up +with innovative solutions to address them. Fortunately, our team managed to address these fundamental problems in the final product. + +### 3. UI +Our GradPad Team has spent a considerable amount of effort on the UI aspect, from choosing the position of the result +display and command box input, to the color theme that is the most pleasing to the audience. There should also be a +special mention to Syafiq for coming up with the logo of GradPad from scratch, personalizing GradPad's Ui to our target +audience. Our team absolutely loves the color theme we have ended up with and we believe our target audience (Computer +Science Undergraduate) will too. + +### 4. Overall +As a whole, we believe that even though this project was rather demanding and time-consuming, we thoroughly enjoyed +working with one another. Right from the start, we helped each other with the setting up of Github and the process of +the project's workflow. All of us were also very encouraging and constantly reviewed each other's pull requests with +comprehensive comments, allowing us to learn from each other's strengths in coding. We are definitely proud of GradPad +, and believe that it will serve its purpose to the fullest potential. diff --git a/docs/UserGuide.md b/docs/UserGuide.md index b91c3bab04d..2bddbd53852 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,176 +3,514 @@ layout: page title: User Guide --- -AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps. * Table of Contents {:toc} +-------------------------------------------------------------------------------------------------------------------- +## GradPad + +We are a team of **Computer Science Undergraduates** working together to solve **module management** and **graduation planning** problems +faced by fellow Computer Science students. Below is the detailed User Guide for effective use of GradPad which can +ease and improve your **module planning process**. + +GradPad is a one-stop solution to **module management** for Computer Science Undergraduates. +Planning for modules has always been a tedious process but it does not have to be. + +The current approach to planning and tracking graduation requirements is to open up tabs after tabs of NUS resources such as +[NUSMods](https://nusmods.com/) and School of Computing +[websites](https://www.comp.nus.edu.sg/programmes/ug/cs/curr/), which can be messy at times. +So, our team has come up with the idea of an **easy-to-use**, **all-in-one application** that +can ease the process of **module management** for Computer Science Undergraduates. + +GradPad **consolidates** the modules you have taken and **displays** the remaining required modules to +ease your module planning process. A **module searching platform** is also included in GradPad, providing easy +**access** to module information. + +This user guide introduces what you can do with GradPad and the steps needed to do them. In addition, +it includes a [quick start guide](#quick-start) that walks you through the installation and set-up process. +With this guide, you'll be ready to use GradPad in no time. + +-------------------------------------------------------------------------------------------------------------------- +## NUSMods integration +![NUSMods](images/nusmods.png) + +To streamline your module searching process with added convenience, GradPad integrates data from [NUSMods](https://nusmods.com/). With this, +you no longer have to visit NUSMods separately to look up module information. Instead, GradPad offers you all that data +in the same app you use to plan your modules. + +We have requested and was granted permission from NUSMods to utilise their platform to retrieve module data. These data +are retrieved in **realtime**, directly from NUSMods. + -------------------------------------------------------------------------------------------------------------------- ## Quick start +Follow the steps below to learn how to get started with GradPad! + 1. Ensure you have Java `11` or above installed in your Computer. -1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases). +1. Download the latest `gradPad.jar` from [here](https://github.com/AY2021S1-CS2103T-T09-1/tp/releases). -1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook. +1. Copy the file to the folder you want to use as the _home folder_ for your GradPad. -1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png) +1. Ensure you have **internet connectivity** to fully utilise GradPad with the latest data from [NUSMods](https://nusmods.com/). -1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
- Some example commands you can try: +1. Double-click the file to start the app. The Main Page similar to the image below should appear in a few seconds. Note + how the app contains some sample data.
- * **`list`** : Lists all contacts. + ![Ui](images/AnnotatedUi.png) - * **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book. +1. Type a command in the _Command Box_ and press Enter to execute it. e.g. typing **`help`** and pressing Enter will + display the help page.
+ Some other example commands you can try: + + * **`required`** : Shows a list of required modules in the CS curriculum. + + * **`search`** `CS2103T` : Searches for module named `CS2103T` from the NUSMods database + (if connected to the internet) or from a local saved file. - * **`delete`**`3` : Deletes the 3rd contact shown in the current list. + * **`add`** `CS2103T` : Adds a module named `CS2103T` to the GradPad. - * **`clear`** : Deletes all contacts. + * **`delete`** `CS2103T` : Deletes the module named `CS2103T` in the current list. * **`exit`** : Exits the app. + + + +
-1. Refer to the [Features](#features) below for details of each command. +**:information_source: Note:**
+* You can still use GradPad without an internet connection. However, you will only be able to access modules +within the NUS Computer Science [curriculum](https://www.comp.nus.edu.sg/programmes/ug/cs/curr/) while you're offline. +* Detailed explanation of each command can be found [here](#commands). +* Refer to the [Feature Summary List](#feature-summary-list) below for a summary of all features. +
-------------------------------------------------------------------------------------------------------------------- -## Features +## Feature Summary List +A consolidated view of GradPad's features is listed in the table below for easy reference. + +
+ +**:information_source: Note:**
+* Italicised words (e.g. *Completed Modules List*) refer to actual sections on the GradPad user interface. +
+ + Features | Description + ----------------------------------------|------------ + Add a Module | Allows you to add any module of choice to the *Completed Modules List* for tracking purposes + View Added Modules | Allows you to check all the modules you've added to *Completed Modules List* + Find Modules in Completed Modules | Allows you to look for modules in *Completed Modules List* using keywords + Delete a Module | Allows you to delete unwanted modules from *Completed Modules List* + Edit a Module | Allows you to edit the details of a module you've already added to *Completed Modules List* + Check Modular Credits | Allows you to check your current modular credit tally + View all Required Modules | Allows you to display all required modules in the Computer Science curriculum onto the *Result Display Box* + View all General Education Modules | Allows you to display all available General Education Modules offered in NUS onto the *Result Display Box* + View all Science Modules | Allows you to display all available Science modules in the Computer Science curriculum onto the *Result Display Box* + Search for a Module | Allows you to search for any module available in NUS and display the module details onto the *Result Display Box* + Find Tags from Completed Modules | Allows you to check all tags that are used in *Completed Modules List* + Clear all Modules | Allows you to delete all the modules from *Completed Modules List* + View Help | Allows you to view a list of all possible commands + Exit the Program | Allows you to exit GradPad + + +Refer to [Commands](#commands) below for details on all commands. + +## Commands + +This section contains detailed explanations of all commands and their respective usages. + +Each command explanation starts with a usage scenario, followed by an explanation of what the command does, and ends +off by showing you how to use it. + +
+ +**:information_source: Notes about the Command Format and Feature Descriptions:**
+ +* When a command requires parameters, they can be entered in any order.
+For example, if the command specifies `edit MODULE_CODE c/NEW_MODULE_CODE t/core`, `edit MODULE_CODE t/core c/NEW_MODULE_CODE +` is also acceptable. + +* When a command does not require parameters, e.g. `help`, adding extraneous words, e.g `help me` will not affect the + command, allowing the command to run as per normal. + +* Highlighted words (e.g. `this`) refer to actual commands. + +* Italicised words (e.g. *Completed Modules List*) refer to actual sections on the GradPad user interface. + +
+ +### Adding a module: `add` + +Scenario:
+You have just completed the CS2101 module, and you want to add the module into GradPad to track your academic progress. +You found the module to be enjoyable so you would like to add tags to remind yourself of how fun the module was. + +The `add` command allows you to add a module you have completed into the *Completed Modules List*. + +You can add a module by specifying a valid module code. You can also include multiple tags using the prefix `t/` but they are optional. +Conveniently, you don't have to specify the module title or modular credits of the module you are adding - GradPad +automatically retrieves them for you using data from NUSMods.
-**:information_source: Notes about the command format:**
+**:information_source: Note:**
+* You cannot add a module that has been previously added as GradPad does not allow duplicate modules. +* You can use multiple words in a tag. However, there should only be a single space between any 2 words. +* Tags **within a single module** are case-insensitive, i.e. "core", "CORE", and "CoRe" are all considered the same. +In such a case, only the first tag amongst a group of duplicates will be added. For e.g. +`add cs2103t t/core t/CORE t/CoRe` results in only "core" being added. + +
+ +To add the module: + +1. Type `add cs2101 t/superbmodule t/superfun` into the *Command Box*, and press **Enter** to execute it.
+![Add1](images/Add1.png) + +2. The *Result Display Box* will display the message "The following module has been successfully added", along with + the details of the module. You will then be able to see the CS2101 module at the bottom of the *Completed Modules List* + .
+![Add2](images/Add2.png) + +### Viewing all added modules: `list` + +Scenario:
+You have filtered the _Completed Modules List_ to show modules whose module codes contain 'cs1', and you wish to +restore the list to view all the modules you have added. + +The `list` command allows you to view all the modules you have added into the _Completed Modules List_ in GradPad +using this command. This is especially useful when you have previously used a command that filters the list (i.e. `find`), and you wish to restore the list to its original state. + +To view all modules: + +1. Type `list` into the _Command Box_, and press **Enter** to execute it. +![List1](images/List1.png) + +2. The _Result Display Box_ will display the message "All your modules have been listed!", and you will be able to +view all your previously added modules in the _Completed Modules List_. +![List2](images/List2.png) + +### Viewing all added tags: `tags` + +Scenario:
+You wish to filter your _Completed Modules List_ to display modules tagged as "foundation". However, you've added +tons of tags to tons of modules and so you can't remember if this tag actually exists. + +The `tags` command allows you to view all the tags currently in your _Completed Modules List_ in + GradPad. This is useful when you want to see what tags you can filter your _Completed Modules List_ by (see the + `find` command below). + +To view all tags: + +1. Type `tags` into the _Command Box_, and press **Enter** to execute it. +![Tags1](images/Tags1.png) + +2. The _Result Display Box_ will display a list of all existing tags. +![Tag2](images/Tags2.png) + +### Editing module details: `edit` + +Scenario:
+When you were a freshman, you added a module with tags "superbmodule" and "superfun". But now that you're graduating, +you actually think that the module was the best you'd taken in NUS. + +The `edit` command allows you to edit the details of a module that you have added into GradPad. + +You can edit a module by specifying the module code of the module in the _Completed Modules List_, followed by the +fields you wish to edit with their respective prefixes, `c/` for new module code, `t/` for new tag. You may edit +multiple fields in a single `edit` command. + +The respective module title and modular credits for a module code will be automatically updated with data from NUSMods. + +
+ + **:information_source: Note:**
+* When you edit tags, instead of changing the descriptions of the existing tags, editing tags replaces + them with new ones. + +* Instead of deleting that module and adding it again with new tags, you can simply edit the module and replace the tags. + +
-* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`. +To edit the tag of an existing module: -* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`. +1. Type `edit cs2101 t/bestmodule` into the _Command Box_, and press **Enter** to execute it.
+![Edit1](images/Edit1.png) -* Items with `…`​ after them can be used multiple times including zero times.
- e.g. `[t/TAG]…​` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc. +2. The _Result Display Box_ will display the message "The following module has been successfully edited", +along with the newly edited details of the module. You will also be able to see that the tags of the +module displayed in the _Completed Modules List_ has been replaced. -* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable. +![Edit2](images/Edit2.png) + +### Finding a specific module or a group of modules: `find` + +Scenario:
+Let's say you have been adding a huge number of modules into GradPad, and you have lost track of the modules you +have added. You want to check and see all MA-coded modules with the "bestmodule" tag. + +The `find` command allows you to filter the _Completed Modules List_ to display the modules that you want to see. +You can do this by specifying parts of the module code of the module(s) you wish to display. +Additionally, you can also specify the tags of the module(s) you wish to display. Likewise, you can also simply +specify parts of a tag instead of the entire tag. + +Instead of scrolling through the long _Completed Modules List_ and checking the modules one by one, you can easily +filter the list to display that module by `find`-ing said module. + +To find the module: + +1. Type `find ma bestmodule` into the _Command Box_, and press **Enter** to execute it.
+![Find1](images/Find1.png) + +2. The _Result Display Box_ will display the message "2 modules found!" and you will be able to see only the modules +whose module codes contain "ma" and modules with "bestmodule" as a tag in the _Completed Modules List_. +![Find2](images/Find2.png) + +### Deleting a Module: `delete` + +Scenario:
+You have added several modules into GradPad but you realised that you accidentally added an additional module 'CS2107' +that you have not completed yet. If you no longer want that module in your _Completed Modules List_, +you can simply delete it. + +The `delete` command allows you to remove a module you have added into GradPad. + +You can delete a module by specifying the **module code** of the module. (Case insensitive) + +To delete the module: + +1. Type `delete cs2107` into the _Command Box_, and press **Enter** to execute it.
+![Delete1](images/Delete1.png) + +2. When you are prompted for a confirmation, type `yes` into the _Command Box_, and press **Enter**.
+![Delete2](images/Delete2.png) + +3. The _Result Display Box_ will display the message "The following module has been successfully deleted" along +with the details of the module you deleted. +![Delete3](images/Delete3.png) + +
+ +**:bulb: Tip:**
+For experienced users, you can use the `fdelete` command instead, to bypass the confirmation step! + +
+ +### Checking total modular credits: `checkmc` + +
+ +**:information_source: Note:**
+A **Modular Credit** (MC) is a unit of the effort, stated in terms of time, expected of a typical student in managing his/her workload, with +an average of 20 MCs per semester.
-### Viewing help : `help` +Scenario:
+ +You want to make sure you have hit the minimum criteria of 70MCs required for applying internship modules or +the 160MCs graduation requirements. + +The `checkmc` command allows you to check the total amount of modular credits you have accumulated so far using this command. +This gives you a rough gauge of the progress of your graduation planning. -Shows a message explaning how to access the help page. +To check total modular credits: -![help message](images/helpMessage.png) +1. Type `checkmc` into the _Command Box_, and press **Enter** to execute it. +![CheckMc1](images/CheckMc1.png) -Format: `help` +2. The _Result Display Box_ will display a message telling you how many modular credits you have accumulated so far. +![CheckMc2](images/CheckMc2.png) +### Checking required modules: `required` -### Adding a person: `add` +Scenario:
+You have added several modules into your GradPad so far but you are unsure if they are part of +the Computer Science curriculum. You can simply check by using the `required` command. -Adds a person to the address book. +The `required` command allows you to check the modules of the Computer Science curriculum you have yet to take, +based on your _Completed Modules List_. -Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​` +
+ +**:bulb: Tip:**
+The `required` command is able to identify equivalent and precluded Modules! (Eg. CS1010X and CS1101S) -
:bulb: **Tip:** -A person can have any number of tags (including 0)
-Examples: -* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` -* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal` +To check required modules: + +1. Type `required` into the _Command Box_, press **Enter** to execute it. +![Required1](images/Required1.png) + +2. The _Result Display Box_ will then display all the modules you have yet to take for each particular field, as shown below. +![Required2](images/Required2.png) -### Listing all persons : `list` +### Checking General Education Modules: `gem` -Shows a list of all persons in the address book. +Scenario:
+You wish to take some GE modules to clear your GE requirement, but you are unsure what modules are available. +You can simply check by using the `gem` command. -Format: `list` +The `gem` command allows you to check all the available General Education (GE) modules that are available in NUS. +To ease your planning, the `gem` command indicates which modules are available in Semester 1 and/or 2. -### Editing a person : `edit` +To check GE modules: -Edits an existing person in the address book. +1. Type `gem` into the _Command Box_, press **Enter** to execute it. +![Gem1](images/Gem1.png) -Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…​` +2. The _Result Display Box_ will then display all the available GE modules that you can take, +categorised into Semester 1 and 2, as shown below. +![Gem2](images/Gem2.png) -* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …​ -* At least one of the optional fields must be provided. -* Existing values will be updated to the input values. -* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative. -* You can remove all the person’s tags by typing `t/` without - specifying any tags after it. +### Checking Science modules: `science` -Examples: -* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively. -* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags. +Scenario:
+You wish to take a Science module to clear your Science requirement, but you forgot what modules are available. +You can simply check by using the `science` command. -### Locating persons by name: `find` +The `science` command allows you to check all the available Science modules of the Computer Science curriculum. -Finds persons whose names contain any of the given keywords. +To check Science modules: -Format: `find KEYWORD [MORE_KEYWORDS]` +1. Type `science` into the _Command Box_, press **Enter** to execute it. +![Science1](images/Science1.png) -* The search is case-insensitive. e.g `hans` will match `Hans` -* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans` -* Only the name is searched. -* Only full words will be matched e.g. `Han` will not match `Hans` -* Persons matching at least one keyword will be returned (i.e. `OR` search). - e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang` +2. The _Result Display Box_ will then display all the available Science modules that you can take, as shown below. +![Science2](images/Science2.png) -Examples: -* `find John` returns `john` and `John Doe` -* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png) +### Searching for a module: `search` -### Deleting a person : `delete` +Scenario:
+After viewing the required modules you have yet to take, you wish to find out more about those modules (Eg. What are they about? +Do they have any pre-requisites?). You can simply look up those details by using the `search` command. -Deletes the specified person from the address book. +The `search` command allows you to search for any module available in NUS. -Format: `delete INDEX` +You can search for a module by specifying the module code of the module. The essential module details will then be retrieved +from NUSMods database directly and displayed in the _Result Display Box_. -* Deletes the person at the specified `INDEX`. -* The index refers to the index number shown in the displayed person list. -* The index **must be a positive integer** 1, 2, 3, …​ +
+ +**:information_source: Note:**
+If you are not connected to the internet, you can only search for modules that are in the NUS Computer Science + curriculum. + +
+ +1. Type `search MA1521` into the _Command Box_, press **Enter** to execute it. +![Search1](images/Search1.png) + +2. The _Result Display Box_ will then display all the relevant information about the module "MA1521", as shown below. +![Search2](images/Search2.png) + +### Clearing all modules in GradPad: `clear` + +Scenario:
+You used GradPad to draft a plan for the modules you're going to take, but now you wish to erase all of that and + start a new plan. Instead of deleting every module one by one, you can simply delete them all at one go. + +The Clear command allows you to erase all modules from the *Completed Modules List* at one go with a single command. + +To clear all modules: + +1. Type `clear` into the _Command Box_, and press **Enter** to execute it.
+![Clear1](images/Clear1.png) + +2. When you are prompted for a confirmation, type `yes` into the _Command Box_, and press **Enter**.
+![Clear2](images/Clear2.png) + +3. The *Result Display Box* will then display the message "GradPad has been cleared!" and the +*Completed Modules List* will now be empty, as shown below. +![Clear3](images/Clear3.png) + +
-Examples: -* `list` followed by `delete 2` deletes the 2nd person in the address book. -* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command. +:bulb: Tip:
+For experienced users, you can use the `fclear` command instead, to bypass the confirmation step! -### Clearing all entries : `clear` +
+ +### Showing the help display: `help` -Clears all entries from the address book. +Scenario:
+You are in the midst of planning your modules, but you suddenly forgot what commands are available to you. +Simply refresh your memory by using the `help` command to see all available commands and their respective functions. -Format: `clear` +The `help` command displays all of GradPad's available commands and how to use them, to you. +This command is useful for first-timers or users who generally do not know how to use GradPad. -### Exiting the program : `exit` +To show the help display: -Exits the program. +1. Type `help` into the _Command Box_, and press **Enter** to execute it.
+![Help1](images/Help1.png) -Format: `exit` +1. The _Result Display Box_ will display all of GradPad's commands along with examples on how to use them.
+![Help2](images/Help2.png) -### Saving the data +### Exiting GradPad: `exit` -AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. +Apart from clicking the "close" button (red button) at the top of the GradPad window, you can exit GradPad using the `exit` command. -### Archiving data files `[coming in v2.0]` +To exit: -_{explain the feature here}_ +1. Type `exit` into the _Command Box_, and press **Enter** to execute it.
+![Exit](images/Exit1.png) + +2. The _Result Display Box_ will display the message "Take care!" and after a 1.5 second delay, the application will terminate.
+![Exit2](images/Exit2.png) -------------------------------------------------------------------------------------------------------------------- ## FAQ **Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder. +**A**: +1. In your old computer, find the `gradPad.json` file within your GradPad home folder and transfer this file +to your new computer. + +2. On your new computer, launch GradPad once. In GradPad's home folder, you should now see that +an empty `gradPad.json` file has been created. + +3. Delete this empty file and replace it with the `gradPad.json` file from your old computer. -------------------------------------------------------------------------------------------------------------------- ## Command summary -Action | Format, Examples ---------|------------------ -**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…​`
e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague` -**Clear** | `clear` -**Delete** | `delete INDEX`
e.g., `delete 3` -**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…​`
e.g.,`edit 2 n/James Lee e/jameslee@example.com` -**Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake` -**List** | `list` -**Help** | `help` +This section is the table of all the commands available, and their respective usage example in GradPad. + +
+ +**:information_source: Notes about the Command summary:**
+ +* Words in curly braces (e.g. `{module code}`) refers to **compulsory** input that is required for the command to function. + +* Words in square brackets (e.g. `[c/module code]`) refers to **optional** input that can be entered. + +* For the `edit` command, at least the module code or tag is required for the command to function. + +
+ +Action | Format | Example +--------|-------|---------- +**Add** | `add {module code} [t/tags]` | `add CS2100 t/core` +**Edit** | `edit {module code} [c/module code] [t/tags]` | `edit cs2103 c/CS2103T t/core` +**Delete** | `delete {module code}` | `delete CS2103T` +**Force Delete** | `fdelete {module code}` | `fdelete CS2103T` +**Completed Modules** | `list` | `list` +**Find** | `find {module code or tag}` | `find CS2103T foundation fun` +**Check MCs** | `checkmc` | `checkmc` +**Required Modules** | `required` | `required` +**General Education Modules** | `gem` | `gem` +**Science Modules** | `science` | `science` +**Search module details** | `search {module code}` | `search CS2103T` +**Check existing Tags** | `tags` | `tags` +**Clear** | `clear` | `clear` +**Force Clear** | `fclear` | `fclear` +**Help** | `help` | `help` +**Exit** | `exit` | `exit` diff --git a/docs/_config.yml b/docs/_config.yml index 6bd245d8f4e..ddbdf582ac9 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,5 +1,5 @@ -title: "AB-3" -theme: minima +title: "GradPad" +theme: jekyll-theme-hacker header_pages: - UserGuide.md @@ -8,7 +8,7 @@ header_pages: markdown: kramdown -repository: "se-edu/addressbook-level3" +repository: "AY2021S1-CS2103T-T09-1/tp" github_icon: "images/github-icon.png" plugins: diff --git a/docs/diagrams/AddModuleTagsSequenceDiagram.puml b/docs/diagrams/AddModuleTagsSequenceDiagram.puml new file mode 100644 index 00000000000..da4880dcba9 --- /dev/null +++ b/docs/diagrams/AddModuleTagsSequenceDiagram.puml @@ -0,0 +1,27 @@ +@startuml +!include style.puml + +box Model MODEL_COLOR_T1 +participant ":GradPad" as GradPad MODEL_COLOR +participant ":UniqueTagMap" as UniqueTagMap MODEL_COLOR +participant ":UniqueModuleList" as UniqueModuleList MODEL_COLOR +end box + +[-> GradPad : addModule(m) +activate GradPad + +GradPad -> UniqueTagMap : checkAndReplaceTags(m.tags) +activate UniqueTagMap + +UniqueTagMap --> GradPad : replacedTagSet +deactivate UniqueTagMap + +GradPad -> UniqueModuleList : addModule(mWithReplacedTags) +activate UniqueModuleList + +UniqueModuleList --> GradPad +deactivate UniqueModuleList + +[<--GradPad +deactivate GradPad +@enduml diff --git a/docs/diagrams/AddSequenceDiagram.puml b/docs/diagrams/AddSequenceDiagram.puml new file mode 100644 index 00000000000..7ab1e82e65d --- /dev/null +++ b/docs/diagrams/AddSequenceDiagram.puml @@ -0,0 +1,132 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant ":AddCommandParser" as AddCommandParser LOGIC_COLOR +participant ":ParserUtil" as ParserUtil LOGIC_COLOR +participant ":ModuleInfoSearcher" as ModuleInfoSearcher LOGIC_COLOR +participant "a:AddCommand" as AddCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Nusmods NUSMODS_COLOR_T1 +participant ":NusmodsDataManager" as NusmodsDataManager NUSMODS_COLOR +participant ":ModuleInfo" as ModuleInfo NUSMODS_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Module" as Module MODEL_COLOR +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("add cs1231") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("add cs1231") +activate GradPadParser + +create AddCommandParser +GradPadParser -> AddCommandParser +activate AddCommandParser + +AddCommandParser --> GradPadParser +deactivate AddCommandParser + +GradPadParser -> AddCommandParser : parse("cs1231") +activate AddCommandParser + +AddCommandParser -> ParserUtil : parseModuleCode("cs1231") +activate ParserUtil + +ParserUtil --> AddCommandParser : code +deactivate ParserUtil + +AddCommandParser -> ModuleInfoSearcher : searchModule(code) +activate ModuleInfoSearcher + +ModuleInfoSearcher -> NusmodsDataManager : getModuleInfo(code) +activate NusmodsDataManager + +NusmodsDataManager --> ModuleInfoSearcher : moduleInfo +deactivate NusmodsDataManager + +ModuleInfoSearcher --> AddCommandParser : moduleInfo +deactivate ModuleInfoSearcher + +AddCommandParser -> ParserUtil : parseModuleTitle() +activate ParserUtil + +ParserUtil -> ModuleInfo : getTitle() +activate ModuleInfo + +ModuleInfo --> ParserUtil : title +deactivate ModuleInfo + +ParserUtil --> AddCommandParser : title +deactivate ParserUtil + +AddCommandParser -> ParserUtil : parseModularCredits() +activate ParserUtil + +ParserUtil -> ModuleInfo : getModuleCredit() +activate ModuleInfo + +ModuleInfo --> ParserUtil : credits +deactivate ModuleInfo + +ParserUtil --> AddCommandParser : credits +deactivate ParserUtil + +AddCommandParser -> ParserUtil : parseTags("") +activate ParserUtil + +ParserUtil --> AddCommandParser : tagList +deactivate ParserUtil + +create Module +AddCommandParser -> Module : Module(code, title, credits, tagList) +activate Module + +Module --> AddCommandParser +deactivate Module + +create AddCommand +AddCommandParser -> AddCommand : AddCommand(Module) +activate AddCommand + +AddCommand --> AddCommandParser : a +deactivate AddCommand + +AddCommandParser --> GradPadParser : a +deactivate AddCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddCommandParser -[hidden]-> GradPadParser +destroy AddCommandParser + +GradPadParser --> LogicManager : a +deactivate GradPadParser + +LogicManager -> AddCommand : execute() +activate AddCommand + +AddCommand -> Model : addModule(Module) +activate Model + +Model --> AddCommand +deactivate Model + +create CommandResult +AddCommand -> CommandResult +activate CommandResult + +CommandResult --> AddCommand +deactivate CommandResult + +AddCommand --> LogicManager : result +deactivate AddCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/ArchitectureDiagram.puml b/docs/diagrams/ArchitectureDiagram.puml index a929d8e40b3..5cdc4d0414d 100644 --- a/docs/diagrams/ArchitectureDiagram.puml +++ b/docs/diagrams/ArchitectureDiagram.puml @@ -11,6 +11,7 @@ Package " "<>{ Class Model MODEL_COLOR Class Main #grey Class Commons LOGIC_COLOR_T2 + Class Nusmods NUSMODS_COLOR } Class "<$user>" as User MODEL_COLOR_T2 @@ -21,11 +22,13 @@ UI -[#green]> Logic UI -right[#green]-> Model Logic -[#blue]-> Storage Logic -down[#blue]-> Model +Logic -right[#blue]-> Nusmods Main -[#grey]-> UI Main -[#grey]-> Logic Main -[#grey]-> Storage Main -up[#grey]-> Model +Nusmods .right.> File Storage .right[STORAGE_COLOR].>File User ..> UI @enduml diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index ef81d18c337..8431456294b 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -7,19 +7,19 @@ Participant ":Logic" as logic LOGIC_COLOR Participant ":Model" as model MODEL_COLOR Participant ":Storage" as storage STORAGE_COLOR -user -[USER_COLOR]> ui : "delete 1" +user -[USER_COLOR]> ui : "delete c/CS2103T" activate ui UI_COLOR -ui -[UI_COLOR]> logic : execute("delete 1") +ui -[UI_COLOR]> logic : execute("delete c/CS2103T") activate logic LOGIC_COLOR -logic -[LOGIC_COLOR]> model : deletePerson(p) +logic -[LOGIC_COLOR]> model : deleteModule(m) activate model MODEL_COLOR model -[MODEL_COLOR]-> logic deactivate model -logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook) +logic -[LOGIC_COLOR]> storage : saveGradPad(gradPad) activate storage STORAGE_COLOR storage -[STORAGE_COLOR]> storage : Save to file diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml index 29076104af3..c3552c550c2 100644 --- a/docs/diagrams/BetterModelClassDiagram.puml +++ b/docs/diagrams/BetterModelClassDiagram.puml @@ -4,18 +4,17 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -AddressBook *-right-> "1" UniquePersonList -AddressBook *-right-> "1" UniqueTagList -UniqueTagList -[hidden]down- UniquePersonList -UniqueTagList -[hidden]down- UniquePersonList +GradPad *-right-> "1" UniqueModuleList +GradPad *-right-> "1" UniqueTagList +UniqueTagList -[hidden]down- UniqueModuleList +UniqueTagList -[hidden]down- UniqueModuleList UniqueTagList *-right-> "*" Tag -UniquePersonList o-right-> Person +UniqueModuleList o-right-> Module -Person -up-> "*" Tag +Module -up-> "*" Tag -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address +Module *--> ModuleCode +Module *--> ModularCredits +Module *--> ModuleName @enduml diff --git a/docs/diagrams/CancelStalledSequenceDiagram.puml b/docs/diagrams/CancelStalledSequenceDiagram.puml new file mode 100644 index 00000000000..ee4a65d1366 --- /dev/null +++ b/docs/diagrams/CancelStalledSequenceDiagram.puml @@ -0,0 +1,30 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +[-> LogicManager : execute("no") +activate LogicManager + +LogicManager -> LogicManager +activate LogicManager + +note left: Set stalledCommand to null + +LogicManager --> LogicManager +deactivate LogicManager + +create CommandResult +LogicManager -> CommandResult +activate CommandResult + +CommandResult --> LogicManager : abortMessage +deactivate CommandResult + +[<--LogicManager : abortMessage +deactivate LogicManager + +@enduml diff --git a/docs/diagrams/CheckMcSequenceDiagram.puml b/docs/diagrams/CheckMcSequenceDiagram.puml new file mode 100644 index 00000000000..c0790b1995e --- /dev/null +++ b/docs/diagrams/CheckMcSequenceDiagram.puml @@ -0,0 +1,66 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant "C:CheckMcCommand" as CheckMcCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "gradpad:GradPad" as GradPad MODEL_COLOR +end box + +[-> LogicManager : execute("checkmc") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("checkmc") +activate GradPadParser + +create CheckMcCommand +GradPadParser -> CheckMcCommand +activate CheckMcCommand + +CheckMcCommand -> GradPadParser : C +deactivate CheckMcCommand + +GradPadParser --> LogicManager : C +deactivate GradPadParser + +LogicManager -> CheckMcCommand : execute() +activate CheckMcCommand + +CheckMcCommand -> Model : getGradPad() +activate Model + +Model --> CheckMcCommand : gradpad +deactivate Model + +CheckMcCommand -> GradPad : getModuleList() +activate GradPad + +GradPad -> CheckMcCommand : modules +deactivate GradPad + +CheckMcCommand -> CheckMcCommand +activate CheckMcCommand +note left: sum up MCs of all modules + +CheckMcCommand -> CheckMcCommand +deactivate CheckMcCommand + +create CommandResult +CheckMcCommand -> CommandResult +activate CommandResult + +CommandResult --> CheckMcCommand +deactivate CommandResult + +CheckMcCommand --> LogicManager +deactivate CheckMcCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml index 7f8fe407f89..f0d53b48dd7 100644 --- a/docs/diagrams/CommitActivityDiagram.puml +++ b/docs/diagrams/CommitActivityDiagram.puml @@ -5,10 +5,10 @@ start 'Since the beta syntax does not support placing the condition outside the 'diamond we place it as the true branch instead. -if () then ([command commits AddressBook]) +if () then ([command commits GradPad]) :Purge redunant states; - :Save AddressBook to - addressBookStateList; + :Save GradPad to + gradPadStateList; else ([else]) endif stop diff --git a/docs/diagrams/ConfirmStalledSequenceDiagram.puml b/docs/diagrams/ConfirmStalledSequenceDiagram.puml new file mode 100644 index 00000000000..b32ca6f5ee4 --- /dev/null +++ b/docs/diagrams/ConfirmStalledSequenceDiagram.puml @@ -0,0 +1,38 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "stalledCommand:DeleteCommand" as DeleteCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("yes") +activate LogicManager + +LogicManager -> DeleteCommand : stalledCommand.execute() +activate DeleteCommand + +DeleteCommand -> Model : deleteModule("CS2103T") +activate Model + +Model --> DeleteCommand +deactivate Model + +create CommandResult +DeleteCommand -> CommandResult +activate CommandResult + +CommandResult --> DeleteCommand : result +deactivate CommandResult + +DeleteCommand --> LogicManager : result +deactivate DeleteCommand + +[<--LogicManager : result +deactivate LogicManager +@enduml diff --git a/docs/diagrams/DeleteModuleTagsSequenceDiagram.puml b/docs/diagrams/DeleteModuleTagsSequenceDiagram.puml new file mode 100644 index 00000000000..3ddfc3263c0 --- /dev/null +++ b/docs/diagrams/DeleteModuleTagsSequenceDiagram.puml @@ -0,0 +1,38 @@ +@startuml +!include style.puml + +box Model MODEL_COLOR_T1 +participant ":GradPad" as GradPad MODEL_COLOR +participant ":UniqueTagMap" as UniqueTagMap MODEL_COLOR +participant ":UniqueModuleList" as UniqueModuleList MODEL_COLOR +participant ":Tag" as Tag MODEL_COLOR +end box + +[-> GradPad : removeModule(m) +activate GradPad + +GradPad -> UniqueTagMap : remove(m.tags) +activate UniqueTagMap + +loop for tag in m.tags + +UniqueTagMap -> Tag : decrementModuleCount() +activate Tag + +Tag --> UniqueTagMap +deactivate Tag + +end + +UniqueTagMap --> GradPad +deactivate UniqueTagMap + +GradPad -> UniqueModuleList : remove(m) +activate UniqueModuleList + +UniqueModuleList --> GradPad +deactivate UniqueModuleList + +[<--GradPad +deactivate GradPad +@enduml diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml index 1dc2311b245..1f9cce379dd 100644 --- a/docs/diagrams/DeleteSequenceDiagram.puml +++ b/docs/diagrams/DeleteSequenceDiagram.puml @@ -3,8 +3,9 @@ box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR +participant ":ParserUtil" as ParserUtil LOGIC_COLOR participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR participant ":CommandResult" as CommandResult LOGIC_COLOR end box @@ -13,22 +14,28 @@ box Model MODEL_COLOR_T1 participant ":Model" as Model MODEL_COLOR end box -[-> LogicManager : execute("delete 1") +[-> LogicManager : execute("delete CS2103T") activate LogicManager -LogicManager -> AddressBookParser : parseCommand("delete 1") -activate AddressBookParser +LogicManager -> GradPadParser : parseCommand("delete CS2103T") +activate GradPadParser create DeleteCommandParser -AddressBookParser -> DeleteCommandParser +GradPadParser -> DeleteCommandParser activate DeleteCommandParser -DeleteCommandParser --> AddressBookParser +DeleteCommandParser --> GradPadParser deactivate DeleteCommandParser -AddressBookParser -> DeleteCommandParser : parse("1") +GradPadParser -> DeleteCommandParser : parse("CS2103T") activate DeleteCommandParser +DeleteCommandParser -> ParserUtil : parseModuleCode("CS2103T") +activate ParserUtil + +ParserUtil --> DeleteCommandParser : code +deactivate ParserUtil + create DeleteCommand DeleteCommandParser -> DeleteCommand activate DeleteCommand @@ -36,19 +43,31 @@ activate DeleteCommand DeleteCommand --> DeleteCommandParser : d deactivate DeleteCommand -DeleteCommandParser --> AddressBookParser : d +DeleteCommandParser --> GradPadParser : d deactivate DeleteCommandParser 'Hidden arrow to position the destroy marker below the end of the activation bar. -DeleteCommandParser -[hidden]-> AddressBookParser +DeleteCommandParser -[hidden]-> GradPadParser destroy DeleteCommandParser -AddressBookParser --> LogicManager : d -deactivate AddressBookParser +GradPadParser --> LogicManager : d +deactivate GradPadParser + +LogicManager -> LogicManager : handleStall() +activate LogicManager + +LogicManager --> LogicManager : confirmationPrompt +deactivate LogicManager + +[<-- LogicManager : confirmationPrompt +deactivate LogicManager + +[-> LogicManager : execute("yes") +activate LogicManager LogicManager -> DeleteCommand : execute() activate DeleteCommand -DeleteCommand -> Model : deletePerson(1) +DeleteCommand -> Model : deleteModule("CS2103T") activate Model Model --> DeleteCommand @@ -64,6 +83,6 @@ deactivate CommandResult DeleteCommand --> LogicManager : result deactivate DeleteCommand -[<--LogicManager +[<--LogicManager : result deactivate LogicManager @enduml diff --git a/docs/diagrams/EditSequenceDiagram.puml b/docs/diagrams/EditSequenceDiagram.puml new file mode 100644 index 00000000000..1e13e6cab2b --- /dev/null +++ b/docs/diagrams/EditSequenceDiagram.puml @@ -0,0 +1,138 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant ":EditCommandParser" as EditCommandParser LOGIC_COLOR +participant ":ParserUtil" as ParserUtil LOGIC_COLOR +participant ":EditModuleDescriptor" as EditModuleDescriptor LOGIC_COLOR +participant ":ModuleInfoSearcher" as ModuleInfoSearcher LOGIC_COLOR +participant "e:EditCommand" as EditCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Nusmods NUSMODS_COLOR_T1 +participant ":NusmodsDataManager" as NusmodsDataManager NUSMODS_COLOR +participant ":ModuleInfo" as ModuleInfo NUSMODS_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("edit cs2103t c/cs2101") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("edit cs2103t c/cs2101") +activate GradPadParser + +create EditCommandParser +GradPadParser -> EditCommandParser +activate EditCommandParser + +EditCommandParser --> GradPadParser +deactivate EditCommandParser + +GradPadParser -> EditCommandParser : parse("cs2103t c/cs2101") +activate EditCommandParser + +EditCommandParser -> ParserUtil : parseModuleCode("cs2103t") +activate ParserUtil + +ParserUtil --> EditCommandParser : code +deactivate ParserUtil + +create EditModuleDescriptor +EditCommandParser -> EditModuleDescriptor +activate EditModuleDescriptor + +EditModuleDescriptor --> EditCommandParser : desc +deactivate EditModuleDescriptor + +EditCommandParser -> ParserUtil : parseModuleCode("cs2101") +activate ParserUtil + +ParserUtil --> EditCommandParser : newCode +deactivate ParserUtil + +EditCommandParser -> ModuleInfoSearcher : searchModule(newCode) +activate ModuleInfoSearcher + +ModuleInfoSearcher -> NusmodsDataManager : getModuleInfo(code) +activate NusmodsDataManager + +NusmodsDataManager --> ModuleInfoSearcher : moduleInfo +deactivate NusmodsDataManager + +ModuleInfoSearcher --> EditCommandParser : moduleInfo +deactivate ModuleInfoSearcher + +EditCommandParser -> EditModuleDescriptor : setModuleCode(newCode) +activate EditModuleDescriptor + +EditModuleDescriptor --> EditCommandParser : +deactivate EditModuleDescriptor + +EditCommandParser -> EditModuleDescriptor : setModuleTitle() +activate EditModuleDescriptor + +EditModuleDescriptor -> ModuleInfo : getTitle() +activate ModuleInfo + +ModuleInfo --> EditModuleDescriptor : title +deactivate ModuleInfo + +EditModuleDescriptor --> EditCommandParser : +deactivate EditModuleDescriptor + +EditCommandParser -> EditModuleDescriptor : setModularCredits() +activate EditModuleDescriptor + +EditModuleDescriptor -> ModuleInfo : getModuleCredit() +activate ModuleInfo + +ModuleInfo --> EditModuleDescriptor : credits +deactivate ModuleInfo + +EditModuleDescriptor --> EditCommandParser : +deactivate EditModuleDescriptor + +create EditCommand +EditCommandParser -> EditCommand : EditCommand(code, desc) +activate EditCommand + +EditCommand --> EditCommandParser : e +deactivate EditCommand + +EditCommandParser --> GradPadParser : e +deactivate EditCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +EditCommandParser -[hidden]-> GradPadParser +destroy EditCommandParser + +GradPadParser --> LogicManager : e +deactivate GradPadParser + +LogicManager -> EditCommand : execute() +activate EditCommand + +EditCommand -> Model : setModule(moduleToEdit, editedModule) +activate Model + +Model --> EditCommand +deactivate Model + +create CommandResult +EditCommand -> CommandResult +activate CommandResult + +CommandResult --> EditCommand +deactivate CommandResult + +EditCommand --> LogicManager : result +deactivate EditCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/FindSequenceDiagram.puml b/docs/diagrams/FindSequenceDiagram.puml new file mode 100644 index 00000000000..14c28dd6824 --- /dev/null +++ b/docs/diagrams/FindSequenceDiagram.puml @@ -0,0 +1,77 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR +participant "f:FindCommand" as FindCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant "c:CompoundFindPredicate" as CompoundFindPredicate MODEL_COLOR +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("find cs foundation") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("find cs foundation") +activate GradPadParser + +create FindCommandParser +GradPadParser -> FindCommandParser +activate FindCommandParser + +FindCommandParser --> GradPadParser +deactivate FindCommandParser + +GradPadParser -> FindCommandParser : parse("cs foundation") +activate FindCommandParser + +create CompoundFindPredicate +FindCommandParser -> CompoundFindPredicate +activate CompoundFindPredicate + +CompoundFindPredicate --> FindCommandParser : c +deactivate CompoundFindPredicate + +create FindCommand +FindCommandParser -> FindCommand : new FindCommand(c) +activate FindCommand + +FindCommand --> FindCommandParser : f +deactivate FindCommand + +FindCommandParser --> GradPadParser : f +deactivate FindCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +FindCommandParser -[hidden]-> GradPadParser +destroy FindCommandParser + +GradPadParser --> LogicManager : f +deactivate GradPadParser + +LogicManager -> FindCommand : execute() +activate FindCommand + +FindCommand -> Model : updateFilteredModuleList(c) +activate Model + +Model --> FindCommand +deactivate Model + +create CommandResult +FindCommand -> CommandResult +activate CommandResult + +CommandResult --> FindCommand +deactivate CommandResult + +FindCommand --> LogicManager : result +deactivate FindCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/GemSequenceDiagram.puml b/docs/diagrams/GemSequenceDiagram.puml new file mode 100644 index 00000000000..d087b323833 --- /dev/null +++ b/docs/diagrams/GemSequenceDiagram.puml @@ -0,0 +1,93 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant "G:GemCommand" as GemCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Storage STORAGE_COLOR_T1 +participant "sem1Storage:GemCommandStorage" as GemCommandStorage STORAGE_COLOR +participant "sem2Storage:GemCommandStorage" as GemCommandStorage2 STORAGE_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("gem") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("gem") +activate GradPadParser + +create GemCommand +GradPadParser -> GemCommand +activate GemCommand + +GemCommand --> GradPadParser : G +deactivate GemCommand + +GradPadParser --> LogicManager : G +deactivate GradPadParser + +LogicManager -> GemCommand : execute() +activate GemCommand + +GemCommand -> GemCommand : setSem1Storage() +activate GemCommand + +create GemCommandStorage +GemCommand -> GemCommandStorage : sem1Storage +activate GemCommandStorage + +GemCommandStorage --> GemCommand : sem1Storage +deactivate GemCommandStorage + +GemCommand -> GemCommandStorage : setGeModules(SEM_1_PATH) +activate GemCommandStorage + +GemCommandStorage --> GemCommand : sem1GeModules +deactivate GemCommandStorage + +deactivate GemCommand + +GemCommand -> GemCommand : setSem2Storage() +activate GemCommand + +create GemCommandStorage2 +GemCommand -> GemCommandStorage2 : sem2Storage +activate GemCommandStorage2 + +GemCommandStorage2 --> GemCommand : sem2Storage +deactivate GemCommandStorage2 + +GemCommand -> GemCommandStorage2 : setGeModules(SEM_2_PATH) +activate GemCommandStorage2 + +GemCommandStorage2 --> GemCommand : sem2GeModules +deactivate GemCommandStorage2 + +deactivate GemCommand + +GemCommand -> Model : hasModule(semXXXGeModules) +activate Model + +Model --> GemCommand : filteredSemXXXGeModules +deactivate Model + +create CommandResult +GemCommand -> CommandResult : filteredSemXXXGeModules +activate CommandResult + +CommandResult --> GemCommand +deactivate CommandResult + +GemCommand --> LogicManager +deactivate GemCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/ListSequenceDiagram.puml b/docs/diagrams/ListSequenceDiagram.puml new file mode 100644 index 00000000000..03fae1f6d4a --- /dev/null +++ b/docs/diagrams/ListSequenceDiagram.puml @@ -0,0 +1,52 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant "L:ListCommand" as ListCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("list") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("list") +activate GradPadParser + +create ListCommand +GradPadParser -> ListCommand +activate ListCommand + +ListCommand -> GradPadParser : L +deactivate ListCommand + +GradPadParser --> LogicManager : L +deactivate GradPadParser + +LogicManager -> ListCommand : execute() +activate ListCommand + +ListCommand -> Model : updateFilteredModuleList(PREDICATE_SHOW_ALL_MODULES) +activate Model + +Model --> ListCommand +deactivate Model + +create CommandResult +ListCommand -> CommandResult +activate CommandResult + +CommandResult --> ListCommand +deactivate CommandResult + +ListCommand --> LogicManager +deactivate ListCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml index 016ef33e2e2..94d2af92ba1 100644 --- a/docs/diagrams/LogicClassDiagram.puml +++ b/docs/diagrams/LogicClassDiagram.puml @@ -8,7 +8,7 @@ package Logic { package Parser { Interface Parser <> -Class AddressBookParser +Class GradPadParser Class XYZCommandParser Class CliSyntax Class ParserUtil @@ -35,8 +35,8 @@ Class HiddenOutside #FFFFFF HiddenOutside ..> Logic LogicManager .up.|> Logic -LogicManager -->"1" AddressBookParser -AddressBookParser .left.> XYZCommandParser: creates > +LogicManager -->"1" GradPadParser +GradPadParser .left.> XYZCommandParser: creates > XYZCommandParser ..> XYZCommand : creates > XYZCommandParser ..|> Parser diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index e85a00d4107..a10f2f9c8af 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -5,52 +5,52 @@ skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR Package Model <>{ -Interface ReadOnlyAddressBook <> +Interface ReadOnlyGradPad <> Interface Model <> Interface ObservableList <> -Class AddressBook -Class ReadOnlyAddressBook +Class GradPad +Class ReadOnlyGradPad Class Model Class ModelManager Class UserPrefs Class ReadOnlyUserPrefs -Package Person { -Class Person -Class Address -Class Email -Class Name -Class Phone -Class UniquePersonList +Package Module { +Class Module +Class ModuleName +Class ModuleCode +Class ModularCredits +Class UniqueModuleList } Package Tag { Class Tag +Class UniqueTagMap } } Class HiddenOutside #FFFFFF HiddenOutside ..> Model -AddressBook .up.|> ReadOnlyAddressBook +GradPad .up.|> ReadOnlyGradPad ModelManager .up.|> Model Model .right.> ObservableList -ModelManager o--> "1" AddressBook +ModelManager o--> "1" GradPad ModelManager o-left-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs -AddressBook *--> "1" UniquePersonList -UniquePersonList o--> "*" Person -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address -Person *--> "*" Tag +GradPad *--> "1" UniqueModuleList +GradPad *--> "1" UniqueTagMap +UniqueTagMap o--> "*" Tag +UniqueModuleList o--> "*" Module +Module *--> ModuleCode +Module *--> ModularCredits +Module *--> ModuleName +Module --> "*" Tag -Name -[hidden]right-> Phone -Phone -[hidden]right-> Address -Address -[hidden]right-> Email +ModuleCode -[hidden]right-> ModularCredits +ModularCredits -[hidden]right-> ModuleName -ModelManager -->"1" Person : filtered list +ModelManager -->"1" Module : filtered list @enduml diff --git a/docs/diagrams/ModelFilteredListClassDiagram.puml b/docs/diagrams/ModelFilteredListClassDiagram.puml new file mode 100644 index 00000000000..10b38858230 --- /dev/null +++ b/docs/diagrams/ModelFilteredListClassDiagram.puml @@ -0,0 +1,22 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor MODEL_COLOR +skinparam classBackgroundColor MODEL_COLOR + +Package Ui { + Class ModuleListPanel UI_COLOR +} + +Package Model { + Class Model + Class FilteredModules +} +Package Logic { + Class XYZCommand LOGIC_COLOR +} + +ModuleListPanel .down[UI_COLOR].> FilteredModules : displays modules from > +Model .left.> FilteredModules : filters > +XYZCommand .up[LOGIC_COLOR].> Model : applies list filters via > +@enduml diff --git a/docs/diagrams/NusmodsClassDiagram.puml b/docs/diagrams/NusmodsClassDiagram.puml new file mode 100644 index 00000000000..9e0f6cc225f --- /dev/null +++ b/docs/diagrams/NusmodsClassDiagram.puml @@ -0,0 +1,21 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor NUSMODS_COLOR +skinparam classBackgroundColor NUSMODS_COLOR + +Interface NusmodsData <> +Class "{abstract}\nDataFetcher" as DataFetcher + +Class DataFetcherManager +Class NusmodsDataManager +Class ModuleSummary +Class ModuleInfo + +NusmodsDataManager -up-|> NusmodsData +NusmodsDataManager .down.> ModuleInfo +NusmodsDataManager .right.> DataFetcher : may get module data from > +DataFetcherManager .left.|> DataFetcher +DataFetcherManager ..> ModuleSummary +DataFetcherManager ..> ModuleInfo : creates > +@enduml diff --git a/docs/diagrams/NusmodsFetchLocalModuleSequenceDiagram.puml b/docs/diagrams/NusmodsFetchLocalModuleSequenceDiagram.puml new file mode 100644 index 00000000000..9db94ac2f4b --- /dev/null +++ b/docs/diagrams/NusmodsFetchLocalModuleSequenceDiagram.puml @@ -0,0 +1,26 @@ +@startuml +!include style.puml + +box Nusmods NUSMODS_COLOR_T1 +participant ":NusmodsDataManager" as NusmodsDataManager NUSMODS_COLOR +participant ":DataFetcherManager" as DataFetcherManager NUSMODS_COLOR +end box + +[-> NusmodsDataManager : getModuleInfo(code) +activate NusmodsDataManager + +NusmodsDataManager -> DataFetcherManager : fetchModuleInfo(code) +activate DataFetcherManager + +DataFetcherManager --> NusmodsDataManager : NusmodsException +deactivate DataFetcherManager + +NusmodsDataManager -> NusmodsDataManager : getModuleInfoFromFile(code) +activate NusmodsDataManager + +NusmodsDataManager --> NusmodsDataManager : moduleInfo +deactivate NusmodsDataManager + +[<--NusmodsDataManager : moduleInfo +deactivate NusmodsDataManager +@enduml diff --git a/docs/diagrams/NusmodsFetchModuleSequenceDiagram.puml b/docs/diagrams/NusmodsFetchModuleSequenceDiagram.puml new file mode 100644 index 00000000000..e915b940ecb --- /dev/null +++ b/docs/diagrams/NusmodsFetchModuleSequenceDiagram.puml @@ -0,0 +1,30 @@ +@startuml +!include style.puml + +box Nusmods NUSMODS_COLOR_T1 +participant ":NusmodsDataManager" as NusmodsDataManager NUSMODS_COLOR +participant ":DataFetcherManager" as DataFetcherManager NUSMODS_COLOR +end box + +box Commons LOGIC_COLOR_T1 +participant ":HttpUtil" as HttpUtil LOGIC_COLOR_T3 +end box + +[-> NusmodsDataManager : getModuleInfo(code) +activate NusmodsDataManager + +NusmodsDataManager -> DataFetcherManager : fetchModuleInfo(code) +activate DataFetcherManager + +DataFetcherManager -> HttpUtil : makeGETRequest(API_URL) +activate HttpUtil + +HttpUtil --> DataFetcherManager : moduleJsonResponse +deactivate HttpUtil + +DataFetcherManager --> NusmodsDataManager : moduleInfo +deactivate DataFetcherManager + +[<--NusmodsDataManager : moduleInfo +deactivate NusmodsDataManager +@enduml diff --git a/docs/diagrams/NusmodsScrapeModuleSequenceDiagram.puml b/docs/diagrams/NusmodsScrapeModuleSequenceDiagram.puml new file mode 100644 index 00000000000..1a02d28dfee --- /dev/null +++ b/docs/diagrams/NusmodsScrapeModuleSequenceDiagram.puml @@ -0,0 +1,49 @@ +@startuml +!include style.puml + +box Nusmods NUSMODS_COLOR_T1 +participant ":DataFetcherManager" as DataFetcherManager NUSMODS_COLOR +end box + +box Commons LOGIC_COLOR_T1 +participant ":HttpUtil" as HttpUtil LOGIC_COLOR_T3 +end box + +[-> DataFetcherManager : fetchAndSaveModules() +activate DataFetcherManager + +DataFetcherManager -> DataFetcherManager : fetchModuleSummaryList() +activate DataFetcherManager + +DataFetcherManager --> DataFetcherManager : summaries +deactivate DataFetcherManager + +DataFetcherManager -> DataFetcherManager : filterModuleSummaries(summaries) +activate DataFetcherManager + +DataFetcherManager --> DataFetcherManager : filteredSummaries +deactivate DataFetcherManager + +DataFetcherManager -> DataFetcherManager : generateModuleInfoMap(summaries) +activate DataFetcherManager + +loop for summary in summaries +DataFetcherManager -> DataFetcherManager : fetchModuleInfo(module) +activate DataFetcherManager + +DataFetcherManager -> HttpUtil : makeGETRequest(API_URL) +activate HttpUtil + +HttpUtil --> DataFetcherManager : moduleJsonResponse +deactivate HttpUtil + +DataFetcherManager -> DataFetcherManager : moduleInfo +deactivate DataFetcherManager +end + +DataFetcherManager -> DataFetcherManager : moduleInfoMap +deactivate DataFetcherManager + +[<--DataFetcherManager : +deactivate DataFetcherManager +@enduml diff --git a/docs/diagrams/RequiredSequenceDiagram.puml b/docs/diagrams/RequiredSequenceDiagram.puml new file mode 100644 index 00000000000..830981a5197 --- /dev/null +++ b/docs/diagrams/RequiredSequenceDiagram.puml @@ -0,0 +1,94 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant "R:RequiredCommand" as RequiredCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Storage STORAGE_COLOR_T1 +participant "Rs:RequiredCommandStorage" as RequiredCommandStorage STORAGE_COLOR +end box + + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("required") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("required") +activate GradPadParser + +create RequiredCommand +GradPadParser -> RequiredCommand +activate RequiredCommand + +RequiredCommand --> GradPadParser : R +deactivate RequiredCommand + +GradPadParser --> LogicManager : R +deactivate GradPadParser + +LogicManager -> RequiredCommand : execute() +activate RequiredCommand + +RequiredCommand -> Model : getGradPad() +activate Model + +Model --> RequiredCommand : GradPad + +RequiredCommand -> Model : getModuleList() + +Model --> RequiredCommand : currentModules +deactivate Model + +RequiredCommand -> RequiredCommand : setStorage() +activate RequiredCommand + +create RequiredCommandStorage +RequiredCommand -> RequiredCommandStorage : RequiredCommandStorage() +activate RequiredCommandStorage + +RequiredCommandStorage --> RequiredCommand :Rs +deactivate RequiredCommandStorage + +RequiredCommand -> RequiredCommandStorage : setRequiredXXX(XXX_PATH) +activate RequiredCommandStorage + +RequiredCommandStorage --> RequiredCommand : requiredXXX +deactivate RequiredCommandStorage + +deactivate RequiredCommand + +RequiredCommand -> RequiredCommand : compareAllGEs() +activate RequiredCommand + +alt allGEsCleared +RequiredCommand -> RequiredCommand : MESSAGE_SUCCESS_GE + +else +RequiredCommand -> RequiredCommand : MESSAGE_FAILURE_GE +end +deactivate RequiredCommand + +RequiredCommand -> RequiredCommand : compareModules(XXX_PATH) +RequiredCommand -> RequiredCommand : compareScience(SCIENCE_PATH) +RequiredCommand -> RequiredCommand : compareInternship(INTERNSHIP_PATH) + +create CommandResult +RequiredCommand -> CommandResult : CommandResult(leftOverModules) +activate CommandResult + +CommandResult --> RequiredCommand +deactivate CommandResult + +RequiredCommand --> LogicManager +deactivate RequiredCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/ScienceSequenceDiagram.puml b/docs/diagrams/ScienceSequenceDiagram.puml new file mode 100644 index 00000000000..6a50d30754b --- /dev/null +++ b/docs/diagrams/ScienceSequenceDiagram.puml @@ -0,0 +1,74 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant "S:ScienceCommand" as ScienceCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Storage STORAGE_COLOR_T1 +participant "Rs:RequiredCommandStorage" as RequiredCommandStorage STORAGE_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("science") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("science") +activate GradPadParser + +create ScienceCommand +GradPadParser -> ScienceCommand +activate ScienceCommand + +ScienceCommand --> GradPadParser : S +deactivate ScienceCommand + +GradPadParser --> LogicManager : S +deactivate GradPadParser + +LogicManager -> ScienceCommand : execute() +activate ScienceCommand + +ScienceCommand -> ScienceCommand : setScienceModules(SCIENCE_PATH) +activate ScienceCommand + +create RequiredCommandStorage +ScienceCommand -> RequiredCommandStorage : RequiredCommandStorage() +activate RequiredCommandStorage + +RequiredCommandStorage --> ScienceCommand : Rs +deactivate RequiredCommandStorage + +ScienceCommand -> RequiredCommandStorage : setRequiredScience(SCIENCE_PATH) +activate RequiredCommandStorage + +RequiredCommandStorage --> ScienceCommand : scienceModules +deactivate RequiredCommandStorage + +deactivate ScienceCommand + +ScienceCommand -> Model : hasModule(scienceModules) +activate Model + +Model --> ScienceCommand : filteredScienceModules +deactivate Model + +create CommandResult +ScienceCommand -> CommandResult : filteredScienceModules +activate CommandResult + +CommandResult --> ScienceCommand +deactivate CommandResult + +ScienceCommand --> LogicManager +deactivate ScienceCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/SearchSequenceDiagram.puml b/docs/diagrams/SearchSequenceDiagram.puml new file mode 100644 index 00000000000..371200c3760 --- /dev/null +++ b/docs/diagrams/SearchSequenceDiagram.puml @@ -0,0 +1,80 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR +participant ":SearchCommandParser" as SearchCommandParser LOGIC_COLOR +participant ":ParserUtil" as ParserUtil LOGIC_COLOR +participant "s:SearchCommand" as SearchCommand LOGIC_COLOR +participant ":ModuleInfoSearcher" as ModuleInfoSearcher LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +[-> LogicManager : execute("search CS2103T") +activate LogicManager + +LogicManager -> GradPadParser : parseCommand("search CS2103T") +activate GradPadParser + +create SearchCommandParser +GradPadParser -> SearchCommandParser +activate SearchCommandParser + +SearchCommandParser --> GradPadParser +deactivate SearchCommandParser + +GradPadParser -> SearchCommandParser : parse("CS2103T") +activate SearchCommandParser + +SearchCommandParser -> ParserUtil : parseModuleCode("CS2103T") +activate ParserUtil + +ParserUtil --> SearchCommandParser : ModuleCode +deactivate ParserUtil + +create SearchCommand +SearchCommandParser -> SearchCommand : SearchCommand("CS2103T") +activate SearchCommand + +SearchCommand --> SearchCommandParser : s +deactivate SearchCommand + +SearchCommandParser --> GradPadParser : s +deactivate SearchCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +SearchCommandParser -[hidden]-> GradPadParser +destroy SearchCommandParser + +GradPadParser --> LogicManager : s +deactivate GradPadParser + +LogicManager -> SearchCommand : execute() +activate SearchCommand + +create ModuleInfoSearcher +SearchCommand -> ModuleInfoSearcher +activate ModuleInfoSearcher + +ModuleInfoSearcher --> SearchCommand +deactivate ModuleInfoSearcher + +SearchCommand -> ModuleInfoSearcher : searchModule("CS2103T") +activate ModuleInfoSearcher + +ModuleInfoSearcher --> SearchCommand : ModuleInfo +deactivate ModuleInfoSearcher + +create CommandResult +SearchCommand -> CommandResult : ModuleInfo +activate CommandResult + +CommandResult --> SearchCommand +deactivate CommandResult + +SearchCommand --> LogicManager : result +deactivate SearchCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/StalledActivityDiagram.puml b/docs/diagrams/StalledActivityDiagram.puml new file mode 100644 index 00000000000..92a7d1b6b3d --- /dev/null +++ b/docs/diagrams/StalledActivityDiagram.puml @@ -0,0 +1,18 @@ +@startuml +start +:User enters command; +if () then ([GradPad awaiting confirmation]) + if () then ([isConfirmation]) + :Execute stalled command; + else ([isCancel]) + :Abort stalled command; +endif +else ([else]) + if () then ([requiresStall]) + :Handle stall; + else ([else]) + :Execute Command; +endif +endif +stop +@enduml diff --git a/docs/diagrams/StalledSequenceDiagram.puml b/docs/diagrams/StalledSequenceDiagram.puml new file mode 100644 index 00000000000..eca1ba76e35 --- /dev/null +++ b/docs/diagrams/StalledSequenceDiagram.puml @@ -0,0 +1,30 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant "stalledCommand:DeleteCommand" as DeleteCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +[-> LogicManager : execute("delete cs2103t") +activate LogicManager + +LogicManager -> LogicManager : handleStall(command, commandText) +activate LogicManager + +create CommandResult +LogicManager -> CommandResult +activate CommandResult + +CommandResult --> LogicManager: confirmationPrompt +deactivate CommandResult + +LogicManager --> LogicManager : confirmationPrompt +deactivate LogicManager + +[<-- LogicManager : confirmationPrompt +deactivate LogicManager + + +@enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index 6adb2e156bf..a8b6f058469 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -6,19 +6,24 @@ skinparam classBackgroundColor STORAGE_COLOR Interface Storage <> Interface UserPrefsStorage <> -Interface AddressBookStorage <> +Interface GradPadStorage <> Class StorageManager Class JsonUserPrefsStorage -Class JsonAddressBookStorage +Class JsonGradPadStorage +Class RequiredCommandStorage +Class GemCommandStorage StorageManager .left.|> Storage StorageManager o-right-> UserPrefsStorage -StorageManager o--> AddressBookStorage +StorageManager o--> GradPadStorage JsonUserPrefsStorage .left.|> UserPrefsStorage -JsonAddressBookStorage .left.|> AddressBookStorage -JsonAddressBookStorage .down.> JsonSerializableAddressBookStorage -JsonSerializableAddressBookStorage .right.> JsonSerializablePerson -JsonSerializablePerson .right.> JsonAdaptedTag +JsonGradPadStorage .left.|> GradPadStorage +JsonGradPadStorage .down.> JsonSerializableGradPad +JsonSerializableGradPad .right.> JsonAdaptedModule +JsonAdaptedModule .right.> JsonAdaptedTag + +RequiredCommandStorage .down.> JsonSerializableGradPad +GemCommandStorage .down.> JsonSerializableGradPad @enduml diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 92746f9fcf7..97fe277716b 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -9,10 +9,9 @@ Interface Ui <> Class "{abstract}\nUiPart" as UiPart Class UiManager Class MainWindow -Class HelpWindow Class ResultDisplay -Class PersonListPanel -Class PersonCard +Class ModuleListPanel +Class ModuleCard Class StatusBarFooter Class CommandBox } @@ -30,29 +29,25 @@ HiddenOutside ..> Ui UiManager .left.|> Ui UiManager -down-> MainWindow -MainWindow --> HelpWindow MainWindow *-down-> CommandBox MainWindow *-down-> ResultDisplay -MainWindow *-down-> PersonListPanel +MainWindow *-down-> ModuleListPanel MainWindow *-down-> StatusBarFooter -PersonListPanel -down-> PersonCard +ModuleListPanel -down-> ModuleCard MainWindow -left-|> UiPart ResultDisplay --|> UiPart CommandBox --|> UiPart -PersonListPanel --|> UiPart -PersonCard --|> UiPart +ModuleListPanel --|> UiPart +ModuleCard --|> UiPart StatusBarFooter --|> UiPart -HelpWindow -down-|> UiPart -PersonCard ..> Model +ModuleCard ..> Model UiManager -right-> Logic MainWindow -left-> Logic -PersonListPanel -[hidden]left- HelpWindow -HelpWindow -[hidden]left- CommandBox CommandBox -[hidden]left- ResultDisplay ResultDisplay -[hidden]left- StatusBarFooter diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml index 96e30744d24..ed205ab56f5 100644 --- a/docs/diagrams/UndoRedoState0.puml +++ b/docs/diagrams/UndoRedoState0.puml @@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000 title Initial state package States { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__gp0:GradPad__" + class State2 as "__gp1:GradPad__" + class State3 as "__gp2:GradPad__" } State1 -[hidden]right-> State2 State2 -[hidden]right-> State3 diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml index 01fcb9b2b96..d3bb8892b2d 100644 --- a/docs/diagrams/UndoRedoState1.puml +++ b/docs/diagrams/UndoRedoState1.puml @@ -3,12 +3,12 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title After command "delete 5" +title After command "delete CS2103T" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__gp0:GradPad__" + class State2 as "__gp1:GradPad__" + class State3 as "__gp2:GradPad__" } State1 -[hidden]right-> State2 diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml index bccc230a5d1..aa80e4fb8d4 100644 --- a/docs/diagrams/UndoRedoState2.puml +++ b/docs/diagrams/UndoRedoState2.puml @@ -3,12 +3,12 @@ skinparam ClassFontColor #000000 skinparam ClassBorderColor #000000 -title After command "add n/David" +title After command "add CS2100" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__gp0:GradPad__" + class State2 as "__gp1:GradPad__" + class State3 as "__gp2:GradPad__" } State1 -[hidden]right-> State2 diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml index ea29c9483e4..290b1769031 100644 --- a/docs/diagrams/UndoRedoState3.puml +++ b/docs/diagrams/UndoRedoState3.puml @@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000 title After command "undo" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__gp0:GradPad__" + class State2 as "__gp1:GradPad__" + class State3 as "__gp2:GradPad__" } State1 -[hidden]right-> State2 diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml index 1b784cece80..0050aa81a4a 100644 --- a/docs/diagrams/UndoRedoState4.puml +++ b/docs/diagrams/UndoRedoState4.puml @@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000 title After command "list" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab2:AddressBook__" + class State1 as "__gp0:GradPad__" + class State2 as "__gp1:GradPad__" + class State3 as "__gp2:GradPad__" } State1 -[hidden]right-> State2 diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml index 88927be32bc..65ac88db645 100644 --- a/docs/diagrams/UndoRedoState5.puml +++ b/docs/diagrams/UndoRedoState5.puml @@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000 title After command "clear" package States <> { - class State1 as "__ab0:AddressBook__" - class State2 as "__ab1:AddressBook__" - class State3 as "__ab3:AddressBook__" + class State1 as "__gp0:GradPad__" + class State2 as "__gp1:GradPad__" + class State3 as "__gp2:GradPad__" } State1 -[hidden]right-> State2 @@ -17,5 +17,5 @@ State2 -[hidden]right-> State3 class Pointer as "Current State" #FFFFF Pointer -up-> State3 -note right on link: State ab2 deleted. +note right on link: State gp2 deleted. @end diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml index 410aab4e412..3d88970ade8 100644 --- a/docs/diagrams/UndoSequenceDiagram.puml +++ b/docs/diagrams/UndoSequenceDiagram.puml @@ -3,42 +3,42 @@ box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":GradPadParser" as GradPadParser LOGIC_COLOR participant "u:UndoCommand" as UndoCommand LOGIC_COLOR end box box Model MODEL_COLOR_T1 participant ":Model" as Model MODEL_COLOR -participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR +participant ":VersionedGradPad" as VersionedGradPad MODEL_COLOR end box [-> LogicManager : execute(undo) activate LogicManager -LogicManager -> AddressBookParser : parseCommand(undo) -activate AddressBookParser +LogicManager -> GradPadParser : parseCommand(undo) +activate GradPadParser create UndoCommand -AddressBookParser -> UndoCommand +GradPadParser -> UndoCommand activate UndoCommand -UndoCommand --> AddressBookParser +UndoCommand --> GradPadParser deactivate UndoCommand -AddressBookParser --> LogicManager : u -deactivate AddressBookParser +GradPadParser --> LogicManager : u +deactivate GradPadParser LogicManager -> UndoCommand : execute() activate UndoCommand -UndoCommand -> Model : undoAddressBook() +UndoCommand -> Model : undoGradPad() activate Model -Model -> VersionedAddressBook : undo() -activate VersionedAddressBook +Model -> VersionedGradPad : undo() +activate VersionedGradPad -VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook) -VersionedAddressBook --> Model : -deactivate VersionedAddressBook +VersionedGradPad -> VersionedGradPad :resetData(ReadOnlyGradPad) +VersionedGradPad --> Model : +deactivate VersionedGradPad Model --> UndoCommand deactivate Model diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml index fad8b0adeaa..1ece74a45a9 100644 --- a/docs/diagrams/style.puml +++ b/docs/diagrams/style.puml @@ -31,6 +31,9 @@ !define STORAGE_COLOR_T3 #806600 !define STORAGE_COLOR_T2 #544400 +!define NUSMODS_COLOR #BD0074 +!define NUSMODS_COLOR_T1 #FFA7DD + !define USER_COLOR #000000 skinparam BackgroundColor #FFFFFFF diff --git a/docs/images/Add1.png b/docs/images/Add1.png new file mode 100644 index 00000000000..be11678be1f Binary files /dev/null and b/docs/images/Add1.png differ diff --git a/docs/images/Add2.png b/docs/images/Add2.png new file mode 100644 index 00000000000..c521cb70507 Binary files /dev/null and b/docs/images/Add2.png differ diff --git a/docs/images/AddModuleTagsSequenceDiagram.png b/docs/images/AddModuleTagsSequenceDiagram.png new file mode 100644 index 00000000000..e1ed803d68b Binary files /dev/null and b/docs/images/AddModuleTagsSequenceDiagram.png differ diff --git a/docs/images/AddSequenceDiagram.png b/docs/images/AddSequenceDiagram.png new file mode 100644 index 00000000000..96d9e009cfc Binary files /dev/null and b/docs/images/AddSequenceDiagram.png differ diff --git a/docs/images/AnnotatedUi.png b/docs/images/AnnotatedUi.png new file mode 100644 index 00000000000..c6db4b94269 Binary files /dev/null and b/docs/images/AnnotatedUi.png differ diff --git a/docs/images/ArchitectureDiagram.png b/docs/images/ArchitectureDiagram.png index 5cdcf67e747..e4abede244f 100644 Binary files a/docs/images/ArchitectureDiagram.png and b/docs/images/ArchitectureDiagram.png differ diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 2f1346869d0..ea90fccabf9 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png index bc7ed18ae29..7611064cea5 100644 Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ diff --git a/docs/images/CancelStalledSequenceDiagram.png b/docs/images/CancelStalledSequenceDiagram.png new file mode 100644 index 00000000000..da0330b4bea Binary files /dev/null and b/docs/images/CancelStalledSequenceDiagram.png differ diff --git a/docs/images/CheckMc1.png b/docs/images/CheckMc1.png new file mode 100644 index 00000000000..2a2521ac910 Binary files /dev/null and b/docs/images/CheckMc1.png differ diff --git a/docs/images/CheckMc2.png b/docs/images/CheckMc2.png new file mode 100644 index 00000000000..d50c1281799 Binary files /dev/null and b/docs/images/CheckMc2.png differ diff --git a/docs/images/CheckMcSequenceDiagram.png b/docs/images/CheckMcSequenceDiagram.png new file mode 100644 index 00000000000..1c4a676ca4a Binary files /dev/null and b/docs/images/CheckMcSequenceDiagram.png differ diff --git a/docs/images/Clear1.png b/docs/images/Clear1.png new file mode 100644 index 00000000000..63a3ec85ffd Binary files /dev/null and b/docs/images/Clear1.png differ diff --git a/docs/images/Clear2.png b/docs/images/Clear2.png new file mode 100644 index 00000000000..42d7f85cc67 Binary files /dev/null and b/docs/images/Clear2.png differ diff --git a/docs/images/Clear3.png b/docs/images/Clear3.png new file mode 100644 index 00000000000..6a961352508 Binary files /dev/null and b/docs/images/Clear3.png differ diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png index 4de4fa4bf2b..642d99e6996 100644 Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ diff --git a/docs/images/ConfirmStalledSequenceDiagram.png b/docs/images/ConfirmStalledSequenceDiagram.png new file mode 100644 index 00000000000..f8e89fcea52 Binary files /dev/null and b/docs/images/ConfirmStalledSequenceDiagram.png differ diff --git a/docs/images/Delete1.png b/docs/images/Delete1.png new file mode 100644 index 00000000000..396a2219e92 Binary files /dev/null and b/docs/images/Delete1.png differ diff --git a/docs/images/Delete2.png b/docs/images/Delete2.png new file mode 100644 index 00000000000..ba4ae4cae55 Binary files /dev/null and b/docs/images/Delete2.png differ diff --git a/docs/images/Delete3.png b/docs/images/Delete3.png new file mode 100644 index 00000000000..5bdab3f2255 Binary files /dev/null and b/docs/images/Delete3.png differ diff --git a/docs/images/DeleteModuleTagsSequenceDiagram.png b/docs/images/DeleteModuleTagsSequenceDiagram.png new file mode 100644 index 00000000000..bd57e20a6a6 Binary files /dev/null and b/docs/images/DeleteModuleTagsSequenceDiagram.png differ diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png index fa327b39618..320e3454431 100644 Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ diff --git a/docs/images/Edit1.png b/docs/images/Edit1.png new file mode 100644 index 00000000000..d2fea33bdee Binary files /dev/null and b/docs/images/Edit1.png differ diff --git a/docs/images/Edit2.png b/docs/images/Edit2.png new file mode 100644 index 00000000000..17d0ffdd4ee Binary files /dev/null and b/docs/images/Edit2.png differ diff --git a/docs/images/EditSequenceDiagram.png b/docs/images/EditSequenceDiagram.png new file mode 100644 index 00000000000..f0b3cbe4088 Binary files /dev/null and b/docs/images/EditSequenceDiagram.png differ diff --git a/docs/images/Exit1.png b/docs/images/Exit1.png new file mode 100644 index 00000000000..e49ed95f1b9 Binary files /dev/null and b/docs/images/Exit1.png differ diff --git a/docs/images/Exit2.png b/docs/images/Exit2.png new file mode 100644 index 00000000000..b91473e70d8 Binary files /dev/null and b/docs/images/Exit2.png differ diff --git a/docs/images/Find1.png b/docs/images/Find1.png new file mode 100644 index 00000000000..4d7fc165f0b Binary files /dev/null and b/docs/images/Find1.png differ diff --git a/docs/images/Find2.png b/docs/images/Find2.png new file mode 100644 index 00000000000..bbcbe93be84 Binary files /dev/null and b/docs/images/Find2.png differ diff --git a/docs/images/FindSequenceDiagram.png b/docs/images/FindSequenceDiagram.png new file mode 100644 index 00000000000..a44252f50ac Binary files /dev/null and b/docs/images/FindSequenceDiagram.png differ diff --git a/docs/images/Gem1.png b/docs/images/Gem1.png new file mode 100644 index 00000000000..80136417e54 Binary files /dev/null and b/docs/images/Gem1.png differ diff --git a/docs/images/Gem2.png b/docs/images/Gem2.png new file mode 100644 index 00000000000..f5ecc0043be Binary files /dev/null and b/docs/images/Gem2.png differ diff --git a/docs/images/GemSequenceDiagram.png b/docs/images/GemSequenceDiagram.png new file mode 100644 index 00000000000..c36f6560e61 Binary files /dev/null and b/docs/images/GemSequenceDiagram.png differ diff --git a/docs/images/Help1.png b/docs/images/Help1.png new file mode 100644 index 00000000000..57bc408f9f9 Binary files /dev/null and b/docs/images/Help1.png differ diff --git a/docs/images/Help2.png b/docs/images/Help2.png new file mode 100644 index 00000000000..657ed509ed8 Binary files /dev/null and b/docs/images/Help2.png differ diff --git a/docs/images/List1.png b/docs/images/List1.png new file mode 100644 index 00000000000..3f9be05aec7 Binary files /dev/null and b/docs/images/List1.png differ diff --git a/docs/images/List2.png b/docs/images/List2.png new file mode 100644 index 00000000000..df426b4c605 Binary files /dev/null and b/docs/images/List2.png differ diff --git a/docs/images/ListSequenceDiagram.png b/docs/images/ListSequenceDiagram.png new file mode 100644 index 00000000000..52fb0b25b1e Binary files /dev/null and b/docs/images/ListSequenceDiagram.png differ diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png index b9e853cef12..32034ad3c6b 100644 Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png index 280064118cf..e1cd848a813 100644 Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ diff --git a/docs/images/ModelFilteredListClassDiagram.png b/docs/images/ModelFilteredListClassDiagram.png new file mode 100644 index 00000000000..2f8198ec16d Binary files /dev/null and b/docs/images/ModelFilteredListClassDiagram.png differ diff --git a/docs/images/NusmodsClassDiagram.png b/docs/images/NusmodsClassDiagram.png new file mode 100644 index 00000000000..6b7694db9f1 Binary files /dev/null and b/docs/images/NusmodsClassDiagram.png differ diff --git a/docs/images/NusmodsFetchLocalModuleSequenceDiagram.png b/docs/images/NusmodsFetchLocalModuleSequenceDiagram.png new file mode 100644 index 00000000000..809c5d53073 Binary files /dev/null and b/docs/images/NusmodsFetchLocalModuleSequenceDiagram.png differ diff --git a/docs/images/NusmodsFetchModuleSequenceDiagram.png b/docs/images/NusmodsFetchModuleSequenceDiagram.png new file mode 100644 index 00000000000..ebc440ff3b1 Binary files /dev/null and b/docs/images/NusmodsFetchModuleSequenceDiagram.png differ diff --git a/docs/images/NusmodsScrapeModuleSequenceDiagram.png b/docs/images/NusmodsScrapeModuleSequenceDiagram.png new file mode 100644 index 00000000000..fcdbce7d23b Binary files /dev/null and b/docs/images/NusmodsScrapeModuleSequenceDiagram.png differ diff --git a/docs/images/Required1.png b/docs/images/Required1.png new file mode 100644 index 00000000000..076d5d387cf Binary files /dev/null and b/docs/images/Required1.png differ diff --git a/docs/images/Required2.png b/docs/images/Required2.png new file mode 100644 index 00000000000..7811fab8414 Binary files /dev/null and b/docs/images/Required2.png differ diff --git a/docs/images/RequiredSequenceDiagram.png b/docs/images/RequiredSequenceDiagram.png new file mode 100644 index 00000000000..6c5f7005eea Binary files /dev/null and b/docs/images/RequiredSequenceDiagram.png differ diff --git a/docs/images/Science1.png b/docs/images/Science1.png new file mode 100644 index 00000000000..3faa9c7af48 Binary files /dev/null and b/docs/images/Science1.png differ diff --git a/docs/images/Science2.png b/docs/images/Science2.png new file mode 100644 index 00000000000..e219bbe0e03 Binary files /dev/null and b/docs/images/Science2.png differ diff --git a/docs/images/ScienceSequenceDiagram.png b/docs/images/ScienceSequenceDiagram.png new file mode 100644 index 00000000000..971fd0534d8 Binary files /dev/null and b/docs/images/ScienceSequenceDiagram.png differ diff --git a/docs/images/Search1.png b/docs/images/Search1.png new file mode 100644 index 00000000000..ac49df7df82 Binary files /dev/null and b/docs/images/Search1.png differ diff --git a/docs/images/Search2.png b/docs/images/Search2.png new file mode 100644 index 00000000000..f1c3dbf7b17 Binary files /dev/null and b/docs/images/Search2.png differ diff --git a/docs/images/SearchSequenceDiagram.png b/docs/images/SearchSequenceDiagram.png new file mode 100644 index 00000000000..15154a0cc63 Binary files /dev/null and b/docs/images/SearchSequenceDiagram.png differ diff --git a/docs/images/StalledActivityDiagram.png b/docs/images/StalledActivityDiagram.png new file mode 100644 index 00000000000..42feef33662 Binary files /dev/null and b/docs/images/StalledActivityDiagram.png differ diff --git a/docs/images/StalledSequenceDiagram.png b/docs/images/StalledSequenceDiagram.png new file mode 100644 index 00000000000..bc34fddf41e Binary files /dev/null and b/docs/images/StalledSequenceDiagram.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index d87c1216820..4c7dea78790 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/Tags1.png b/docs/images/Tags1.png new file mode 100644 index 00000000000..d5e38952bb7 Binary files /dev/null and b/docs/images/Tags1.png differ diff --git a/docs/images/Tags2.png b/docs/images/Tags2.png new file mode 100644 index 00000000000..607f5f3870c Binary files /dev/null and b/docs/images/Tags2.png differ diff --git a/docs/images/Ui.png b/docs/images/Ui.png index 5bd77847aa2..37a632c99ce 100644 Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 7b4b3dbea45..116d5a880cb 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png index 8f7538cd884..f25a8d66a2e 100644 Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png index df9908d0948..88aa54b36ba 100644 Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png index 36519c1015b..ba6b5b74dbf 100644 Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png index 19959d01712..a8760691d20 100644 Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png index 4c623e4f2c5..da27507494d 100644 Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png index 84ad2afa6bd..ba798dd478b 100644 Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png index 6addcd3a8d9..91612c9c1ed 100644 Binary files a/docs/images/UndoSequenceDiagram.png and b/docs/images/UndoSequenceDiagram.png differ diff --git a/docs/images/add.png b/docs/images/add.png new file mode 100644 index 00000000000..33d9a2bb6d7 Binary files /dev/null and b/docs/images/add.png differ diff --git a/docs/images/checkmc.png b/docs/images/checkmc.png new file mode 100644 index 00000000000..9584c9f2997 Binary files /dev/null and b/docs/images/checkmc.png differ diff --git a/docs/images/delete.png b/docs/images/delete.png new file mode 100644 index 00000000000..91b96ad4770 Binary files /dev/null and b/docs/images/delete.png differ diff --git a/docs/images/edit.png b/docs/images/edit.png new file mode 100644 index 00000000000..ec628802eaf Binary files /dev/null and b/docs/images/edit.png differ diff --git a/docs/images/exit.png b/docs/images/exit.png new file mode 100644 index 00000000000..6941cde8a30 Binary files /dev/null and b/docs/images/exit.png differ diff --git a/docs/images/find.png b/docs/images/find.png new file mode 100644 index 00000000000..a0401355a40 Binary files /dev/null and b/docs/images/find.png differ diff --git a/docs/images/help.png b/docs/images/help.png new file mode 100644 index 00000000000..62f7e654c12 Binary files /dev/null and b/docs/images/help.png differ diff --git a/docs/images/list.png b/docs/images/list.png new file mode 100644 index 00000000000..f1708794ae6 Binary files /dev/null and b/docs/images/list.png differ diff --git a/docs/images/mhdsyfq.png b/docs/images/mhdsyfq.png new file mode 100644 index 00000000000..d8006632906 Binary files /dev/null and b/docs/images/mhdsyfq.png differ diff --git a/docs/images/nusmods.png b/docs/images/nusmods.png new file mode 100644 index 00000000000..1b52d92eb1a Binary files /dev/null and b/docs/images/nusmods.png differ diff --git a/docs/images/nusmods_small.png b/docs/images/nusmods_small.png new file mode 100644 index 00000000000..41d3dd85081 Binary files /dev/null and b/docs/images/nusmods_small.png differ diff --git a/docs/images/save.png b/docs/images/save.png new file mode 100644 index 00000000000..e2e8fe978ab Binary files /dev/null and b/docs/images/save.png differ diff --git a/docs/images/shaokiat.png b/docs/images/shaokiat.png new file mode 100644 index 00000000000..0a3261d2fe8 Binary files /dev/null and b/docs/images/shaokiat.png differ diff --git a/docs/images/silvernitro.png b/docs/images/silvernitro.png new file mode 100644 index 00000000000..f70f1e2b004 Binary files /dev/null and b/docs/images/silvernitro.png differ diff --git a/docs/images/yan-soon.png b/docs/images/yan-soon.png new file mode 100644 index 00000000000..62c0ed37edc Binary files /dev/null and b/docs/images/yan-soon.png differ diff --git a/docs/index.md b/docs/index.md index 7601dbaad0d..f9e1dee2965 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,24 @@ --- layout: page -title: AddressBook Level-3 +title: GradPad --- -[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions) -[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3) +[![CI Status](https://github.com/AY2021S1-CS2103T-T09-1/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2021S1-CS2103T-T09-1/tp/actions) +[![codecov](https://codecov.io/gh/AY2021S1-CS2103T-T09-1/tp/branch/master/graph/badge.svg?token=fUjXb3CBD3)](https://codecov.io/gh/AY2021S1-CS2103T-T09-1/tp) ![Ui](images/Ui.png) -**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). +**GradPad is a desktop application for managing your NUS modules.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). -* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). -* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. +GradPad is a one-stop solution to **module management** for Computer Science Undergraduates. +Planning for modules has always been a tedious process but it does not have to be. + +GradPad **consolidates** the modules you have taken and **displays** the remaining required modules to +ease your module planning process. A **module searching platform** is also included in GradPad, providing easy +**navigation** of modules. + +* If you are interested in using GradPad, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start). +* If you are interested about developing GradPad, the [**Developer Guide**](DeveloperGuide.html) is a good place to start. **Acknowledgements** diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index 1f1e9e6f6db..00000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: page -title: John Doe's Project Portfolio Page ---- - -## Project: AddressBook Level 3 - -AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. - -Given below are my contributions to the project. - -* **New Feature**: Added the ability to undo/redo previous commands. - * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. - * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. - * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. - * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}* - -* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys. - -* **Code contributed**: [RepoSense link]() - -* **Project management**: - * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub - -* **Enhancements to existing features**: - * Updated the GUI color scheme (Pull requests [\#33](), [\#34]()) - * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]()) - -* **Documentation**: - * User Guide: - * Added documentation for the features `delete` and `find` [\#72]() - * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]() - * Developer Guide: - * Added implementation details of the `delete` feature. - -* **Community**: - * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() - * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) - * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) - * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]()) - -* **Tools**: - * Integrated a third party library (Natty) to the project ([\#42]()) - * Integrated a new Github plugin (CircleCI) to the team repo - -* _{you can add/remove categories in the list above}_ diff --git a/docs/team/mhdsyfq.md b/docs/team/mhdsyfq.md new file mode 100644 index 00000000000..b00795ebf4c --- /dev/null +++ b/docs/team/mhdsyfq.md @@ -0,0 +1,103 @@ +--- +layout: page +title: Muhammad Syafiq Bin Abas's Project Portfolio Page +--- + +## Project: GradPad + +GradPad provides an all-in-one solution to **Module Management** for Computer Science Undergraduates. It +**consolidates** all the processes required for students to **plan their modules** and **track their academic progress** +into a single platform. The first of its kind - GradPad offers a **collaboration** like no other, allowing students to +manage their modules more efficiently without the need to use several platforms all at once. Users interact with +GradPad using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created with JavaFX. + +Given below are my contributions to the project. + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=mhdsyfq&sort=groupTitle&sortWithin=title&since=2020-08-14&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + +* **New Features Implemented**: + * Added the ability to choose to `delete`/`clear` with a confirmation prompt, or to force delete or + force clear using `fdelete`/`fclear`. + + * What it does:
+ Allows users to provide confirmation whether or not they want to proceed with deleting or clearing + data, and also allows users to force delete or clear data without a confirmation prompt. + + * Justification:
+ This feature is significant because users can make mistakes in certain commands that results in them + losing data and the app should provide a convenient way for users to avoid making those mistakes by prompting users + for a confirmation before executing the commands. Some users (usually regulars or experts), however, may find it + troublesome to have to constantly provide confirmation, so the app should also provide a way for users to + instantly execute these commands. + + * Highlights:
+ This enhancement of adding a confirmation prompt affects some existing commands and commands to be + added in future. The implementation was fairly challenging and it required an in-depth analysis of design alternatives + as there is a need to stall the original command, prompt for a confirmation, and then execute or stop the execution + of the command (based on the confirmation provided). Also, there was a need to create a `YesCommand` which accepts any + of `y`, `ye`, or `yes` as a confirmation. After figuring out the implementation, however, the extension to other + existing commands was relatively straightforward. + + * Added the ability to check accumulated Modular Credits (MCs) using `checkmc`. + + * What it does:
+ Allows users to check how many Modular Credits they have attained based on the modules that they have + completed/added into GradPad. + + * Justification:
+ This feature improves the application slightly as users might want to occasionally check how much + MCs they have attained so far so as to gauge how close they are to graduation without having to check the MCs for each + module and manually calculate. + +* **Enhancements to features implemented by peers**: + * Improved `gem` and `science` features to support auto update [\#182](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/182) + +* **Enhancements to existing features**: + + * Refactored the Address Book 3 `ui` package and components [\#37](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/37) + * Improved flexibility of `find` feature [\#77](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/77) + * Improved implementation of `add` and `edit` features [\#111](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/111) + * Added a 1.5 second delay before closing GradPad window for `exit` feature [\#95](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/95) + * Added assertions to the `core`, `logic` and `module` packages [\#92](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/92) + * Refactored Index package [\#219](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/219) + * Changed the entire outlook of the Graphical User Interface (GUI) + * Changed arrangement of GUI components [\#51](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/51) + * Updated GUI color scheme [\#66](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/66) + * Added introduction display with original GradPad logo [\#127](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/127) + +* **Contributions to team-based tasks**: + * Came up with product name + * Changed product icon + * Designed GradPad logo + * Designed and added images with mark-ups for the User Guide + * Documented Non-Functional Requirements and Glossary to the Developer Guide + * Consolidated all messages into a single class + * Updated User Guide according to peers' and tutor's comments + * Improved readability and clarity for result display messages + * Standardised JavaDoc comments + +* **Documentation**: + * User Guide: + * Added documentation for `help`,`add` and `find` features [\#24](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/24) + * Updated command descriptions [\#102](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/102) + + * Developer Guide: + * Added documentation for `find` feature, including sequence diagram [\#62](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/62) + * Added documentation for integration of NUSMods for `add` and `edit` features [\#214](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/214) + * Added documentation for Command Stalling feature [\#217](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/217) + * Updated documentation for `Ui` component, including class diagram [\#62](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/62) + * Updated documentation for manual testing [\#87](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/87) + * Updated documentation for `find` feature [\#215](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/215) + * Updated documentation for `delete` feature [\#217](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/217) + + +* **Community**: + * Assisted in testing and reporting bugs for another team's product:
+ [\#1](https://github.com/mhdsyfq/ped/issues/1), + [\#2](https://github.com/mhdsyfq/ped/issues/2), + [\#3](https://github.com/mhdsyfq/ped/issues/3), + [\#4](https://github.com/mhdsyfq/ped/issues/4), + [\#5](https://github.com/mhdsyfq/ped/issues/5), + [\#6](https://github.com/mhdsyfq/ped/issues/6), + [\#7](https://github.com/mhdsyfq/ped/issues/7), + [\#8](https://github.com/mhdsyfq/ped/issues/8) diff --git a/docs/team/shaokiat.md b/docs/team/shaokiat.md new file mode 100644 index 00000000000..e2ff81c00da --- /dev/null +++ b/docs/team/shaokiat.md @@ -0,0 +1,76 @@ +--- +layout: page +title: Lim Shao Kiat's Project Portfolio Page +--- + +## Project: GradPad + +GradPad is a one-stop solution to **module management** for Computer Science Undergraduates. +GradPad **consolidates** the modules you have taken and **displays** the remaining required modules to +ease your module planning process. A **module searching platform** is also included in GradPad, providing easy +**navigation** of modules. + +Given below are my contributions to the project. + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=shaokiat&sort=groupTitle&sortWithin=title&since=2020-08-14&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=zoom&zA=shaokiat&zR=AY2021S1-CS2103T-T09-1%2Ftp%5Bmaster%5D&zACS=239.02341137123747&zS=2020-08-14&zFS=t09&zU=2020-11-05&zMG=false&zFTF=commit&zFGS=groupByRepos&zFR=false) +* **New Feature**: Added a `search` feature to search for modules from NUSMods and display it to the user. [\#100](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/100) + * What it does: Allows users to search for module details using module code and displaying all module information + onto the Result Display. Module information are fetch directly from NUSMods if internet is available, else it will + be fetched from local saved JSON file. + + * Justification: This feature is required for users to look up relevant module details that they want to find out + about when planning for which modules to take. This command displays the module code, module title, modular credits, + semesters, descriptions, prerequisites and preclusion directly from NUSMods. + + * Highlights: To implement this feature, I created a logic class `ModuleInfoSearcher` to utilize the nusmods package + previously created by my team mates. This logic class make method calls `NusmodsDataManager` to retrieve module + information directly from NUSMods using the NUSMods API. The search command then utilize `ModuleInfoSearcher` class + to search for module information and display the information accordingly in the Result Display. + +* **Team tasks**: + * Updated the User Guide according to Peers and Tutors comments + * Updated the project's logfile to gradpad.log + * Added introduction section to the user guide. + +* **Project management**: + * Recorded comments by Peers and Tutors with regards to GradPad especially on User Guide and Developer Guide. + * Addressed issues on User Guide from mock PE. + * Reviews and comments to team mates PR. [Example: \#111](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/111) + +* **Enhancements to existing features**: + * Refactored the `Delete` feature and command to take in module code as parameters instead of index. [\#120](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/120) + * Refactored the `Model` package and component of AddressBook into GradPad. [\#55](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/55) + * Added assertions to `StorageManager`. [\#105](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/105) + * Added semester data field to `ModuleInfo` class. [\#174](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/174) + +* **Documentation**: + * User Guide: + * Added Ui Markup for User Guide. [\#52](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/52) + * Added documentation for the v1.2 feature `delete` [\#23](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/23) + * Added documentation for the v1.3 feature `search` [\#75](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/75) + * Added documentation for the v1.3 feature `required` [\#75](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/75) + * Added introduction and NUSMods section to User Guide. [\#52](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/52) & [\#130](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/130) + * Updated documentation with comments from CS2101 Tutor and CS2103T TA. [\#130](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/130) + * Updated command summary in documentation. [\#75](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/75) + * Updated feature summary list into table form. [\#75](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/75) + * Updated documentation with issues reported from mock PE for v1.4. [\#172](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/172) + + * Developer Guide: + * Refactored the `Model` component class diagram and description. [\#55](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/55) + * Added implementation details of the `delete` feature. [\#55](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/55) + * Refactored the `Undo/Redo` proposed implementation. [\#75](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/75) + * Added use cases for GradPad in the documentation. [\#75](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/75) + +* **Review/mentoring contributions**: + * PRs reviewed (with non-trivial review comments): [\#58](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/58), + [\#35](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/35), + [\#111](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/111) + * Assisted teammates with any Git queries or issues, specifically on SourceTree. + +* **Community**: + * Assisted in testing and reporting bugs for another team's product: + [\#1](https://github.com/shaokiat/ped/issues/1), + [\#2](https://github.com/shaokiat/ped/issues/2), + [\#3](https://github.com/shaokiat/ped/issues/3), + [\#4](https://github.com/shaokiat/ped/issues/4), + [\#5](https://github.com/shaokiat/ped/issues/5) diff --git a/docs/team/silvernitro.md b/docs/team/silvernitro.md new file mode 100644 index 00000000000..187d4795af3 --- /dev/null +++ b/docs/team/silvernitro.md @@ -0,0 +1,131 @@ +--- +layout: page +title: Lau Siaw Sam's Project Portfolio Page +--- + +## Project: GradPad + +GradPad is a one-stop solution to **module management** for Computer Science Undergraduates. +GradPad **consolidates** the modules you have taken and **displays** the remaining required modules to +ease your module planning process. A **module searching platform** is also included in GradPad, providing easy +**navigation** of modules. + +Given below are my contributions to the project. + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=silvernitro&sort=groupTitle&sortWithin=title&since=2020-08-14&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + +* **New Feature**: Implemented the back-end logic to fetch and use module data from the NUSMods API. + * What it does: Allows GradPad to send HTTP requests to the public NUSMods API to retrieve module summaries + and specific module information data. Additionally, it also has a script to scrape all CS modules to save locally. + + * Justification: This feature is core to GradPad's module searching platform as it allows users to view + the most up-to-date information, that can't be achieved if GradPad simply used an archive of pre-fetched data. + Additionally, since GradPad must not be reliant on an internet connection, we also had to scrape and save CS + module data to a local file and ship that with GradPad releases, so that users can still search for CS modules + even when offline. + + * Highlights: The feature was not trivial to implement as it consists of several major parts: fetching module + summaries, fetching module information, deserializing JSON data received into Java objects, serializing these + objects into JSON save files compatible with GradPad, and also making module info available even without an internet + connection. On the whole, I found it difficult to handle API requests and JSON data in Java and had to read up + quite a bit on the topic. + To make it easier for other developers to use NUSMods data, + I designed the NUSMods package with a high degree of encapsulation and a lean public interface. + As such, client code elsewhere in GradPad can simply pass in module codes and get back module info using simple + function calls. There is no need to handle the fetching, storing, or the fall-back to local data (when offline) + anywhere else in GradPad. + + * Credits: Code reuse was minimal. However, the basic logic to make HTTP GET requests is rather boilerplate and may + seem to be the same in any Java application. + +* **New Feature**: Added a feature to allow filtering of modules by tags + * What it does: Allows users to key in tags that they wish to search for, and view all modules with those tags. + + * Justification: This feature allows users to use tags to organize their list of modules and navigate that list + conveniently when their no. of modules are large. + + * Highlights: To implement this feature, I had to create a new predicate to test if a module contained certain tags. + After that, I had to tweak the existing `find` command to allow it to search by tags too. However, in order to + retain the original functionality of searching by module code keywords, I had to come up with a way to combine + both search predicates. In order to make things more extensible, I decided to create a new compound predicate class + that handles the chaining of multiple predicates. + +
+ +* **New Feature**: Added a command to allow users to view all tags in GradPad + * What it does: Allows users to view a list of all the tags they've added. + + * Justification: This feature allows users to check if a certain tag exists. This is especially useful when they + need to know what tags they can use to filter their list of modules (see feature above). + + * Highlights: The implementation of this feature is not as straightforward as it sounds. In the original AB3 + project, a module's tags were implemented by storing a list of `Tag` objects within each `Module`. + However, this provided no way to easily retrieve all tags without duplicates. To do so, one would + have to iterate through every module in GradPad, iterate through each module's list of `Tag` objects, filter them, + and then display them. + As such, I re-implemented the tags feature by creating a central class to hold a collection of unique tags in + GradPad. All `Module` objects thus reference unique `Tag` objects within this collection, rather than store their + own duplicate copies of `Tag`s. Printing out all tags would just involve printing this collection out. This + also meant that I had to rework the implementation for the addition, editing, and deletion of modules to use + this new collection of unique tags. + +* **Team tasks**: + * Set up assertions in Gradle. + * Updated the project's readme page to reflect the project's features and direct all hyperlinks to GradPad pages. + * Updated GradPad's Jekyll config (remove AB3-specific content). + * Added feature summary list and command summary table to the user guide. + +* **Project management**: + * Managed releases `v1.3-trial` and `v1.3` (2 releases) on GitHub + +* **Enhancements to existing features**: + * Refactored the entire AB3 `Person` package and its containing classes to GradPad's `Module` package. + * Added assertions to the `NUSMods` package. + * Allow multi-word tags and substring module searches by tags. + * Add case-insensitive check for duplicate tags when users add a module. + +* **Documentation**: + * User Guide: + * Added documentation for the feature `tag` [\#131](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/131) + * Added documentation for the feature `edit` [\#64](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/64) + * Added documentation for the feature `clear` [\#216](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/216) + * Added documentation to explain the automatic addition of module titles and modular credits + [\#83](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/64) + * Updated documentation for the features `add`, `find`, `edit` + [\#131](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/131) + * Updated introduction to include the purpose of the guide + [\#113](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/113) + * Developer Guide: + * Added architecture details and design considerations for the `NUSMods` component, including a class diagram. + [\#78](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/78) + * Added implementation details of the `tags` feature, including sequence diagrams. + [\#192](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/192) + * Added implementations details of GradPad's NUSMods integration, including sequence diagrams. + [\#198](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/198) + * Added implementation details of the `edit`, `list`, `checkmc`, `required`, `search` command features, including + all sequence diagrams. + [\#78](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/78) & + [\#42](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/42) + * Updated the `Storage` component class diagram. + [\#42](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/42) + +* **Review/mentoring contributions**: + * PRs reviewed (with non-trivial review comments): [\#94](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/94), + [\#97](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/97), + [\#111](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/111), + [\#133](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/133), + [\#169](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/169), + [\#176](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/176), + [\#197](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/197) + * Assisted teammates with any Git queries or issues. + * Assisted in the program design of adding confirmation prompts when executing `delete` and `clear` commands. + +* **Community**: + * Assisted in testing and reporting bugs for another team's product: + [\#1](https://github.com/Silvernitro/ped/issues/1), + [\#2](https://github.com/Silvernitro/ped/issues/2), + [\#3](https://github.com/Silvernitro/ped/issues/3), + [\#4](https://github.com/Silvernitro/ped/issues/4), + [\#5](https://github.com/Silvernitro/ped/issues/5), + [\#6](https://github.com/Silvernitro/ped/issues/6), + [\#7](https://github.com/Silvernitro/ped/issues/7) diff --git a/docs/team/yan-soon.md b/docs/team/yan-soon.md new file mode 100644 index 00000000000..6172f9860ae --- /dev/null +++ b/docs/team/yan-soon.md @@ -0,0 +1,117 @@ +--- +layout: page +title: Soon Xiang, Yan's Project Portfolio Page +--- + +## Project: GradPad + +GradPad is an offline computer application meant to help Computer Science students from the +National University of Singapore (NUS) plan their modules with more ease. All module information is +displayed through our simple and organised Graphical User Interface (GUI) created with JavaFX. +GradPad is also optimised for users who prefer working on a Command Line Interface (CLI). It is written +in Java, and has about 13k LoC. + + +Given below are my contributions to the project. + +* **New Feature**: Added `required` command to check left-over required modules from the Computer Science Curriculum. + + * What it does: Allows the user to check any undone required modules by cross-referring their current list of completed modules + against the list of all the required modules that we store within GradPad. Modules are split into separate categories + (Eg. Foundation, GE, Etc) for enhanced readability. The command also accounts for equivalent modules and preclusion (Eg. CS1010X & CS1101S). + + * Justification: This feature enhances the product significantly as users no longer have to refer manually to the NUS + website, just to see a list of modules that they have not completed. Also, they do not have to manually filter our their + completed modules, just to check what are the left-over modules, saving them loads of time during their module planning. + + * Highlights: This enhancement is a vital selling point of GradPad and will affect our future features. As the command + deals with a lot of data and functionality, it required an in-depth analysis of design alternatives and OOP. The implementation + was also tedious as it required a lot of testing. Initially, we used the provided JsonGradPadStorage class to read JSON + file paths. However, we realised that our JAR release was not able to load the JSON files properly in runtime, due to + pathing issues. Hence, with help from fellow teammate Lau Siaw Sam and some further study, we managed to find another + way to read JSON files during runtime with the help of a ClassLoader, allowing our app to run smoothly during our release. + + * Credits: [Read a file from resources folder](https://mkyong.com/java/java-read-a-file-from-resources-folder/) + +* **New Feature**: Added `science` and `gem` commands to check all the available Science and General Education Modules +under the Computer Science Curriculum and in NUS respectively. + + * What it does: Allows the user to check all the undone and available Science and General Education modules + in the curriculum, based on their current list of modules accomplished. + + * Justification: This feature enhances the product as users no longer have to refer to the School website just to view + the available Science Modules. It is separated from the `required` command from making the required command too + cluttered, thus improving overall user experience. Separating the two commands also makes it easier to update our storage + as we can now update our database for science modules without touching the other databases. Furthermore, General Education + modules are also split according to Semester Availability which saves users more time. + + * Highlights: This enhancement is vital to GradPad as it is part of our core `required` command feature. The command deals + with a fair bit of data and testing, making the implementation slightly difficult. Faced the same issue as described above + regarding accessing JSON files in our JAR release. + + * Credits: [Read a file from resources folder](https://mkyong.com/java/java-read-a-file-from-resources-folder/) + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=yan-soon&sort=groupTitle&sortWithin=title&since=2020-08-14&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + +* **Project management**: + * Minutes Taker during meetings and consultations. + * Assign weekly workload to team. + * Provide feedback constantly, to teammate's code. + [Comments made](https://nus-cs2103-ay2021s1.github.io/dashboards/contents/tp-comments.html) + +* **Enhancements to existing features**: + * Refactored `Command`, `Parser` and `Storage` Component of AB3 code base + (Pull request [\#35](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/35)) + * Updated `help` command to display instructions directly instead of a link to the UG. + (Pull request [\#70](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/70)) + * Added Assertions to Model Component. + (Pull request [\#99](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/99)) + * Added tests to existing features to improve overall Test Coverage. + (Pull requests [\#197](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/197), + [\#204](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/204)) + +* **Documentation**: + * User Guide: + * Added documentation for the features `required`, `science`, `gem`, `checkmc`, and `exit`. + (Pull requests [\#16](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/16), + [\#117](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/117), + [\#134](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/134)) + * Used Markdown to write Tips and Notes to make UG more visually stunning. + (Pull requests [\#134](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/134), + [\#218](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/218)) + * Improved sentence structuring and language use in UG to make it more user-centric. + (Pull requests [\#45](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/45), + [\#70](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/70), + [\#117](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/117), + [\#134](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/134)) + + * Developer Guide: + * Added implementation details for the features `add`, `required`, `science` and `gem` + and the Storage Component. + (Pull requests [\#45](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/45), + [\#180](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/180) + [\#218](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/218)) + * Added Introduction and 'About This Guide' section to the DG. + (Pull request [\#70](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/70)) + * Added Target User Profile, Value Proposition, User Stories and Use Cases to the DG. + (Pull request [\#19](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/19)) + * Added Manual Testing for all features to the DG. + (Pull request [\#180](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/180)) + * Refactored `Logic` component portion of DG. + (Pull request [\#45](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/45)) + +* **Community**: + * PRs reviewed (with non-trivial review comments): + [\#100](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/100), + [\#111](https://github.com/AY2021S1-CS2103T-T09-1/tp/pull/111) + * Reported bugs and suggestions for other teams in the class + (examples: [\#1](https://github.com/yan-soon/ped/issues/1), + [\#2](https://github.com/yan-soon/ped/issues/2), + [\#3](https://github.com/yan-soon/ped/issues/3), + [\#4](https://github.com/yan-soon/ped/issues/4), + [\#5](https://github.com/yan-soon/ped/issues/5), + [\#6](https://github.com/yan-soon/ped/issues/6), + [\#7](https://github.com/yan-soon/ped/issues/7), + [\#8](https://github.com/yan-soon/ped/issues/8), + [\#9](https://github.com/yan-soon/ped/issues/9), + [\#10](https://github.com/yan-soon/ped/issues/10)) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index e5cfb161b73..88611aed77e 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -15,15 +15,15 @@ import seedu.address.commons.util.StringUtil; import seedu.address.logic.Logic; import seedu.address.logic.LogicManager; -import seedu.address.model.AddressBook; +import seedu.address.model.GradPad; import seedu.address.model.Model; import seedu.address.model.ModelManager; -import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.ReadOnlyGradPad; import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.UserPrefs; import seedu.address.model.util.SampleDataUtil; -import seedu.address.storage.AddressBookStorage; -import seedu.address.storage.JsonAddressBookStorage; +import seedu.address.storage.GradPadStorage; +import seedu.address.storage.JsonGradPadStorage; import seedu.address.storage.JsonUserPrefsStorage; import seedu.address.storage.Storage; import seedu.address.storage.StorageManager; @@ -48,7 +48,7 @@ public class MainApp extends Application { @Override public void init() throws Exception { - logger.info("=============================[ Initializing AddressBook ]==========================="); + logger.info("=============================[ Initializing GradPad ]==========================="); super.init(); AppParameters appParameters = AppParameters.parse(getParameters()); @@ -56,8 +56,8 @@ public void init() throws Exception { UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath()); UserPrefs userPrefs = initPrefs(userPrefsStorage); - AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath()); - storage = new StorageManager(addressBookStorage, userPrefsStorage); + GradPadStorage gradPadStorage = new JsonGradPadStorage(userPrefs.getGradPadFilePath()); + storage = new StorageManager(gradPadStorage, userPrefsStorage); initLogging(config); @@ -69,25 +69,25 @@ public void init() throws Exception { } /** - * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found, - * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book. + * Returns a {@code ModelManager} with the data from {@code storage}'s GradPad and {@code userPrefs}.
+ * The data from the sample GradPad will be used instead if {@code storage}'s GradPad is not found, + * or an empty GradPad will be used instead if errors occur when reading {@code storage}'s GradPad. */ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { - Optional addressBookOptional; - ReadOnlyAddressBook initialData; + Optional gradPadOptional; + ReadOnlyGradPad initialData; try { - addressBookOptional = storage.readAddressBook(); - if (!addressBookOptional.isPresent()) { - logger.info("Data file not found. Will be starting with a sample AddressBook"); + gradPadOptional = storage.readGradPad(); + if (!gradPadOptional.isPresent()) { + logger.info("Data file not found. Will be starting with a sample GradPad"); } - initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook); + initialData = gradPadOptional.orElseGet(SampleDataUtil::getSampleGradPad); } catch (DataConversionException e) { - logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Data file not in the correct format. Will be starting with an empty GradPad"); + initialData = new GradPad(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); - initialData = new AddressBook(); + logger.warning("Problem while reading from the file. Will be starting with an empty GradPad"); + initialData = new GradPad(); } return new ModelManager(initialData, userPrefs); @@ -151,7 +151,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { + "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with an empty GradPad"); initializedPrefs = new UserPrefs(); } @@ -167,13 +167,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) { @Override public void start(Stage primaryStage) { - logger.info("Starting AddressBook " + MainApp.VERSION); + logger.info("Starting GradPad " + MainApp.VERSION); ui.start(primaryStage); } @Override public void stop() { - logger.info("============================ [ Stopping Address Book ] ============================="); + logger.info("============================ [ Stopping GradPad ] ============================="); try { storage.saveUserPrefs(model.getUserPrefs()); } catch (IOException e) { diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/address/commons/core/GuiSettings.java index ba33653be67..1cc07c88ff2 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/seedu/address/commons/core/GuiSettings.java @@ -10,8 +10,8 @@ */ public class GuiSettings implements Serializable { - private static final double DEFAULT_HEIGHT = 600; - private static final double DEFAULT_WIDTH = 740; + public static final double DEFAULT_HEIGHT = 600; + public static final double DEFAULT_WIDTH = 740; private final double windowWidth; private final double windowHeight; @@ -30,6 +30,8 @@ public GuiSettings() { * Constructs a {@code GuiSettings} with the specified height, width and position. */ public GuiSettings(double windowWidth, double windowHeight, int xPosition, int yPosition) { + assert(windowWidth > 0); + assert(windowHeight > 0); this.windowWidth = windowWidth; this.windowHeight = windowHeight; windowCoordinates = new Point(xPosition, yPosition); diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/address/commons/core/LogsCenter.java index 431e7185e76..4fdc19471a6 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/seedu/address/commons/core/LogsCenter.java @@ -18,7 +18,7 @@ public class LogsCenter { private static final int MAX_FILE_COUNT = 5; private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB - private static final String LOG_FILE = "addressbook.log"; + private static final String LOG_FILE = "gradpad.log"; private static Level currentLogLevel = Level.INFO; private static final Logger logger = LogsCenter.getLogger(LogsCenter.class); private static FileHandler fileHandler; @@ -31,10 +31,20 @@ public class LogsCenter { * is requested again from the LogsCenter. */ public static void init(Config config) { + assert(config != null); currentLogLevel = config.getLogLevel(); logger.info("currentLogLevel: " + currentLogLevel); } + /** + * Retrieves the currentLogLevel attribute. + * + * @return currentLogLevel attribute of type Level. + */ + public Level getCurrentLogLevel() { + return currentLogLevel; + } + /** * Creates a logger with the given name. */ diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java index 1deb3a1e469..bf2cf3c2944 100644 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/seedu/address/commons/core/Messages.java @@ -5,9 +5,230 @@ */ 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!"; + // module components constraints + public static final String MESSAGE_CONSTRAINTS_CREDITS = + "Modular credits should only contain numbers, and it should be either 1 or 2 digits long."; + public static final String MESSAGE_CONSTRAINTS_CODE = "A module code must have 2 or more characters as " + + "its prefix followed by 1 or more digits as its numerical code. It can optionally end with 1 or " + + "more characters as a suffix. It is also case-insensitive."; + public static final String MESSAGE_CONSTRAINTS_TITLE = "Module titles should only contain alphanumeric " + + "characters and spaces."; + public static final String MESSAGE_CONSTRAINTS_TAG = "Tag descriptions should be alphanumeric and non-empty."; + // general + public static final String MESSAGE_NEED_HELP = "If you need help, type \"help\"."; + public static final String MESSAGE_MORE_INFO = "For more information, type \"help\"."; + public static final String MESSAGE_EMPTY_FIELD = "Please enter a command.\n\n" + + MESSAGE_NEED_HELP; + public static final String MESSAGE_UNKNOWN_COMMAND = "You have entered an unknown command. Please try " + + "again.\n\n" + MESSAGE_NEED_HELP; + public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Please use the correct format for the " + + "following command: %1$s"; + public static final String MESSAGE_DUPLICATE_MODULE = "Module with module code %1$s already exists!"; + public static final String MESSAGE_INVALID_MODULE = "Module with module code %1$s cannot be found in " + + "GradPad!"; + public static final String MESSAGE_EMPTY_GRADPAD = "GradPad is empty!"; + public static final String MESSAGE_MODULES_FOUND_OVERVIEW = "%1$d modules found!"; + public static final String MESSAGE_INVALID_MODULE_CODE = "%1$s is an invalid module code. Please try" + + " again.\n\n" + + "Note:\n" + MESSAGE_CONSTRAINTS_CODE; + public static final String MESSAGE_INVALID_TAG = "\"%1$s\" is an invalid tag. Please try again.\n\n" + + "Note:\n" + MESSAGE_CONSTRAINTS_TAG; + public static final String LINE = "----------------------------------------------------------------------" + + "--------------------------------------\n\n"; + + // ModuleInfoSearcher + public static final String MESSAGE_FAILED_TO_FIND_MODULE = "Failed to find module: %s"; + public static final String MESSAGE_EMPTY_SEARCH = "Search is empty"; + + // add command + public static final String ADD_COMMAND_WORD = "add"; + public static final String MESSAGE_ADD_USAGE = ADD_COMMAND_WORD + "\n\n" + + "Format:\nadd MODULE_CODE [t/TAG]...\n\nNote:\n" + + "\u2022 [ ] indicate optional fields.\n" + + "\u2022 ... indicate fields that may have multiple instances.\n\n" + + MESSAGE_MORE_INFO; + public static final String MESSAGE_ADD_SUCCESS = "The following module has been successfully added:\n\n" + + "%1$s"; + + // checkmc command + public static final String CHECKMC_COMMAND_WORD = "checkmc"; + public static final String MESSAGE_CHECKMC_SUCCESS = "You have accumulated a total of %.1f MCs so " + + "far!"; + + // clear command + public static final String CLEAR_COMMAND_WORD = "clear"; + public static final String FORCE_CLEAR_COMMAND_WORD = "fclear"; + public static final String MESSAGE_CLEAR_SUCCESS = "GradPad has been cleared!"; + public static final String MESSAGE_CLEAR_CONFIRMATION = "Are you sure you wish to clear all modules? " + + "(yes/no)"; + + // delete command + public static final String DELETE_COMMAND_WORD = "delete"; + public static final String FORCE_DELETE_COMMAND_WORD = "fdelete"; + public static final String MESSAGE_DELETE_USAGE = DELETE_COMMAND_WORD + "\n\n" + + "Format:\ndelete MODULE_CODE\n\n" + + MESSAGE_MORE_INFO; + public static final String MESSAGE_FORCE_DELETE_USAGE = FORCE_DELETE_COMMAND_WORD + "\n\n" + + "Format:\nfdelete MODULE_CODE\n\n" + + MESSAGE_MORE_INFO; + public static final String MESSAGE_DELETE_SUCCESS = "The following module has been successfully " + + "deleted:\n\n%1$s"; + public static final String MESSAGE_DELETE_CONFIRMATION = "Are you sure you wish to delete the following" + + " module? (yes/no)\n\n"; + + // edit command + public static final String EDIT_COMMAND_WORD = "edit"; + public static final String MESSAGE_EDIT_USAGE = EDIT_COMMAND_WORD + "\n\n" + + "Format:\nedit MODULE_CODE [c/NEW_MODULE_CODE] [t/TAG]...\n\nNote:\n" + + "\u2022 At least 1 field to edit must be specified.\n" + + "\u2022 [ ] indicate optional fields.\n" + + "\u2022 ... indicate fields that may have multiple instances.\n\n" + + MESSAGE_MORE_INFO; + public static final String MESSAGE_EDIT_SUCCESS = "The following module has been successfully edited:" + + "\n\n%1$s\n\nEdited module:\n\n%2$s"; + public static final String MESSAGE_NOT_EDITED = "You must provide at least one field to edit!"; + public static final String MESSAGE_ALL_EDIT_FIELDS_SAME = "The new fields provided have the same values as the " + + "current ones."; + + // exit command + public static final String EXIT_COMMAND_WORD = "exit"; + public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Take care!"; + + // find command + public static final String FIND_COMMAND_WORD = "find"; + public static final String MESSAGE_FIND_USAGE = FIND_COMMAND_WORD + "\n\n" + + "Format:\nfind [KEYWORD]... [TAG]...\n\nNote:\n" + + "\u2022 At least 1 keyword or tag to find must be specified.\n" + + "\u2022 [ ] indicate optional fields.\n" + + "\u2022 ... indicate fields that may have multiple instances.\n\n" + + MESSAGE_MORE_INFO; + + // help command + public static final String HELP_COMMAND_WORD = "help"; + public static final String ADD_COMMAND = "To add a module:\tType \"add\" followed by a valid module " + + "code and tags.\n" + + "\t\t\t\t(Tags are optional and you can have any number of tags)\n\n" + + "\t\t\t\tExample(s):\tadd cs1231\n" + + "\t\t\t\t\t\t\tadd cs1231 t/Foundation t/Core\n\n"; + public static final String DELETE_COMMAND = "To delete a module:\tType \"delete\" followed by a valid " + + "module code.\n\n" + + "\t\t\t\tNote:\n" + "\t\t\t\tThis command prompts for a confirmation before deleting.\n\n" + + "\t\t\t\tExample(s):\tdelete cs1231\n\n"; + public static final String FORCE_DELETE_COMMAND = "To force delete" + "\t\tType \"fdelete\" followed by" + + " a valid module code.\n" + + "a module:\n" + + "\t\t\t\tNote:\n" + "\t\t\t\tThis command does not prompt for a confirmation before\n" + + "\t\t\t\tdeleting.\n\n" + + "\t\t\t\tExample(s):\tfdelete cs1231\n\n"; + public static final String EDIT_COMMAND = "To edit a module:\tType \"edit\" followed by a valid module " + + "code and the fields\n" + + "\t\t\t\tyou wish to edit (at least 1 field must be provided). You can\n" + + "\t\t\t\tonly edit the module code and tags of a module by using the\n" + + "\t\t\t\tprefixes \"c/\" and \"t/\" respectively.\n\n" + + "\t\t\t\tNote:\n" + "\t\t\t\tEditing tags replaces existing tags with new ones instead of\n" + + "\t\t\t\tchanging their respective descriptions. You can remove tags of a\n" + + "\t\t\t\tmodule simply by including the aforementioned prefix without a\n" + + "\t\t\t\tdescription as one of the edit fields, i.e., \"t/\".\n\n" + + "\t\t\t\tExample(s):\tedit cs1231 c/cs2100\n" + + "\t\t\t\t\t\t\tedit cs1231 c/cs2100 t/Foundation\n" + + "\t\t\t\t\t\t\tedit cs1231 t/ (to remove tags)\n\n"; + public static final String FIND_COMMAND = "To find a" + "\t\t\tType \"find\" followed by the respective " + + "keywords or tags.\n" + + "specific module" + "\t\t(You can specify multiple keywords or tags)\n" + + "or a group of\n" + + "modules with" + "\t\tNote:\n" + + "common tags" + "\t\tKeywords can be specified as a sequence of characters of a\n" + + "or keywords:" + "\t\tmodule code whereas tags must be specified fully.\n\n" + + "\t\t\t\tExample(s):\tfind cs1231\n" + + "\t\t\t\t\t\t\tfind cs st (to find modules which module codes\n" + + "\t\t\t\t\t\t\tcontain \"cs\" or \"st\")\n" + + "\t\t\t\t\t\t\tfind foundation (to find modules with\n" + + "\t\t\t\t\t\t\t\"foundation\" as a tag)\n\n"; + public static final String SEARCH_COMMAND = "To view details" + "\t\tType \"search\" followed by a " + + "valid module code.\n" + + "of a module:\n" + + "\t\t\t\tExample(s):\tsearch cs1231\n\n"; + public static final String REQUIRED_COMMAND = "To view all" + "\t\t\tType \"required\".\n" + + "your required\nmodules:\n\n"; + public static final String SCIENCE_COMMAND = "To view all" + "\t\t\tType \"science\".\n" + + "available Science\n" + + "modules:" + "\t\t\tNote:\n" + + "\t\t\t\tThis command shows a list of Science modules you can take\n" + + "\t\t\t\tto satisfy the Science component of your module requirements.\n" + + "\t\t\t\tOnce you have completed one of the modules specified in the\n" + + "\t\t\t\tlist, this command will be of zero significance to you.\n\n"; + public static final String GEM_COMMAND = "To view all" + "\t\t\tType \"gem\".\n" + + "available GE\n" + + "modules:" + "\t\t\tNote:\n" + + "\t\t\t\tThis command shows a list of General Education (GE) modules you\n" + + "\t\t\t\tcan take to satisfy your University Level Requirements. Once you\n" + + "\t\t\t\thave completed one module for each of the five GE pillars, this\n" + + "\t\t\t\tcommand will be of zero significance to you.\n\n"; + public static final String CHECKMC_COMMAND = "To check\t\t\tType \"checkmc\".\n" + + "your total MCs:\n\n"; + public static final String TAG_COMMAND = "To view all" + "\t\t\tType \"tags\".\n" + + "your tags:\n\n"; + public static final String LIST_COMMAND = "To list all" + "\t\t\tType \"list\".\n" + + "your completed\nmodules:\n\n"; + public static final String CLEAR_COMMAND = "To clear GradPad:\tType \"clear\".\n\n" + + "\t\t\t\tNote:\n" + "\t\t\t\tThis command prompts for a confirmation before clearing.\n\n"; + public static final String FORCE_CLEAR_COMMAND = "To force clear" + "\t\tType \"fclear\".\n" + + "GradPad:\n" + + "\t\t\t\tNote:\n" + "\t\t\t\tThis command does not prompt for a confirmation before\n" + + "\t\t\t\tclearing.\n\n"; + public static final String EXIT_COMMAND = "To exit:\t\t\tType \"exit\"."; + + public static final String SHOWING_HELP_MESSAGE = ADD_COMMAND + LINE + DELETE_COMMAND + LINE + + FORCE_DELETE_COMMAND + LINE + EDIT_COMMAND + LINE + FIND_COMMAND + LINE + SEARCH_COMMAND + LINE + + REQUIRED_COMMAND + LINE + SCIENCE_COMMAND + LINE + GEM_COMMAND + LINE + CHECKMC_COMMAND + LINE + + TAG_COMMAND + LINE + LIST_COMMAND + LINE + CLEAR_COMMAND + LINE + FORCE_CLEAR_COMMAND + LINE + + EXIT_COMMAND; + + // list command + public static final String LIST_COMMAND_WORD = "list"; + public static final String MESSAGE_LIST_SUCCESS = "All your modules have been listed!"; + + // required command + public static final String REQUIRED_COMMAND_WORD = "required"; + + // gem command + public static final String GEM_COMMAND_WORD = "gem"; + public static final String MESSAGE_GEM_SUCCESS = "--------------- Available GE Modules ---------------"; + public static final String MESSAGE_GEM_FAILURE = "There was an error loading the required GE Modules."; + + // science command + public static final String SCIENCE_COMMAND_WORD = "science"; + public static final String MESSAGE_SCIENCE_SUCCESS = "--------------- Available Science Modules " + + "---------------"; + public static final String MESSAGE_FAILURE_SCIENCE = "Oh no, there was an error loading the required " + + "Science Modules..."; + + // search command + public static final String SEARCH_COMMAND_WORD = "search"; + public static final String MESSAGE_SEARCH_USAGE = SEARCH_COMMAND_WORD + "\n\n" + + "Format:\nsearch MODULE_CODE\n\n" + + MESSAGE_MORE_INFO; + public static final String MESSAGE_SEARCH_SUCCESS = "Module details for %1$s \n\n" + + "Module Title: %3$s \n" + + "Modular Credits: %2$s\n" + + "Semesters: %7$s \n\n" + + "Module Description: \n%4$s \n\n" + + "Preclusion(s): \n%5$s\n\n" + + "Prerequisite(s): \n%6$s\n"; + + // tags command + public static final String TAGS_COMMAND_WORD = "tags"; + public static final String MESSAGE_TAGS_SUCCESS = "All tags:\n"; + public static final String MESSAGE_NO_TAGS = "You have not included any tags."; + + // yes command + public static final String YES_COMMAND_WORD = "yes"; + public static final String YE_COMMAND_WORD = "ye"; + public static final String Y_COMMAND_WORD = "y"; + public static final String MESSAGE_NO_CONFIRMATION = "There is nothing to confirm!"; + + // logic manager messages + public static final String FILE_OPS_ERROR_MESSAGE = "Could not save data to file: "; + public static final String MESSAGE_CONFIRMATION_CANCEL = "Command aborted - "; } diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/address/commons/core/index/Index.java deleted file mode 100644 index 19536439c09..00000000000 --- a/src/main/java/seedu/address/commons/core/index/Index.java +++ /dev/null @@ -1,54 +0,0 @@ -package seedu.address.commons.core.index; - -/** - * Represents a zero-based or one-based index. - * - * {@code Index} should be used right from the start (when parsing in a new user input), so that if the current - * component wants to communicate with another component, it can send an {@code Index} to avoid having to know what - * base the other component is using for its index. However, after receiving the {@code Index}, that component can - * convert it back to an int if the index will not be passed to a different component again. - */ -public class Index { - private int zeroBasedIndex; - - /** - * Index can only be created by calling {@link Index#fromZeroBased(int)} or - * {@link Index#fromOneBased(int)}. - */ - private Index(int zeroBasedIndex) { - if (zeroBasedIndex < 0) { - throw new IndexOutOfBoundsException(); - } - - this.zeroBasedIndex = zeroBasedIndex; - } - - public int getZeroBased() { - return zeroBasedIndex; - } - - public int getOneBased() { - return zeroBasedIndex + 1; - } - - /** - * Creates a new {@code Index} using a zero-based index. - */ - public static Index fromZeroBased(int zeroBasedIndex) { - return new Index(zeroBasedIndex); - } - - /** - * Creates a new {@code Index} using a one-based index. - */ - public static Index fromOneBased(int oneBasedIndex) { - return new Index(oneBasedIndex - 1); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Index // instanceof handles nulls - && zeroBasedIndex == ((Index) other).zeroBasedIndex); // state check - } -} diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java index 19124db485c..a473b43bd86 100644 --- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java +++ b/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java @@ -10,12 +10,4 @@ public class IllegalValueException extends Exception { public IllegalValueException(String message) { super(message); } - - /** - * @param message should contain relevant information on the failed constraint(s) - * @param cause of the main exception - */ - public IllegalValueException(String message, Throwable cause) { - super(message, cause); - } } diff --git a/src/main/java/seedu/address/commons/util/HttpUtil.java b/src/main/java/seedu/address/commons/util/HttpUtil.java new file mode 100644 index 00000000000..bebde4a7ea2 --- /dev/null +++ b/src/main/java/seedu/address/commons/util/HttpUtil.java @@ -0,0 +1,41 @@ +package seedu.address.commons.util; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +import seedu.address.nusmods.exceptions.NusmodsException; + +/** + * Utilities for HTTP requests. + */ +public class HttpUtil { + public static final HttpUtil SINGLETON = new HttpUtil(); + /** + * Makes a HTTP GET request to a URL and returns the response as a string. + * + * @param urlString The URL to send the GET request to. + * @return The HTTP response as a string. + * @throws NusmodsException an error occurs while making the request. + */ + //CHECKSTYLE.OFF: AbbreviationAsWordInName + public String makeGETRequest(String urlString) throws NusmodsException { + //CHECKSTYLE.ON: AbbreviationAsWordInName + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .timeout(Duration.ofSeconds(3)) + .uri(URI.create(urlString)) + .GET() + .build(); + + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + return response.body(); + } catch (IOException | InterruptedException ex) { + throw new NusmodsException(ex); + } + } +} diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/address/commons/util/JsonUtil.java index 8ef609f055d..a796f02653b 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/seedu/address/commons/util/JsonUtil.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -12,6 +13,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; @@ -20,8 +22,12 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import javafx.collections.ObservableList; import seedu.address.commons.core.LogsCenter; import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.module.Module; +import seedu.address.storage.JsonSerializableGradPad; /** * Converts a Java object instance to JSON and vice versa @@ -140,4 +146,21 @@ public Class handledType() { } } + /** + * Converts a given JSON file via its runtime path, into a list of Modules. + * @param file Converted file content of type String. + * @return List of modules taken from the JSON file via the runtime path. + * @throws IOException When the file is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public static ObservableList getModulesFromJsonFile(String file) throws IOException, IllegalValueException { + JsonSerializableGradPad jsonGradPad = JsonUtil.fromJsonString(file, JsonSerializableGradPad.class); + return jsonGradPad.toModelType().getModuleList(); + } + + public static Map getPreclusionMapFromJsonFile(String file) throws IOException { + TypeReference> targetType = new TypeReference<>() {}; + return objectMapper.readValue(file, targetType); + } } diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 61cc8c9a1cb..3505fa5a43d 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -5,7 +5,6 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Arrays; /** * Helper functions for handling strings. @@ -13,29 +12,41 @@ public class StringUtil { /** - * Returns true if the {@code sentence} contains the {@code word}. - * Ignores case, but a full word match is required. + * Returns true if the {@code moduleCode} contains the {@code charSequence}. + * Ignores case, a partial match is required. *
examples:
-     *       containsWordIgnoreCase("ABc def", "abc") == true
-     *       containsWordIgnoreCase("ABc def", "DEF") == true
-     *       containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
+     *       containsCharSequenceIgnoreCase("ABc", "abc") == true
+     *       containsCharSequenceIgnoreCase("def", "DEF") == true
+     *       containsCharSequenceIgnoreCase("ABc", "AB") == true // partial match
      *       
- * @param sentence cannot be null - * @param word cannot be null, cannot be empty, must be a single word + * @param moduleCode cannot be null + * @param charSequence cannot be null, cannot be empty, must be a single word */ - public static boolean containsWordIgnoreCase(String sentence, String word) { - requireNonNull(sentence); - requireNonNull(word); + public static boolean containsCharSequenceIgnoreCase(String moduleCode, String charSequence) { + requireNonNull(moduleCode); + requireNonNull(charSequence); - String preppedWord = word.trim(); - checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty"); - checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word"); + String preppedModuleCode = moduleCode.trim().toUpperCase(); + String preppedCharSequence = charSequence.trim().toUpperCase(); + checkArgument(!preppedCharSequence.isEmpty(), "CharSequence parameter cannot be empty"); + checkArgument(preppedCharSequence.split("\\s+").length == 1, "CharSequence parameter should be a " + + "single word"); - String preppedSentence = sentence; - String[] wordsInPreppedSentence = preppedSentence.split("\\s+"); + return preppedModuleCode.contains(preppedCharSequence); + } - return Arrays.stream(wordsInPreppedSentence) - .anyMatch(preppedWord::equalsIgnoreCase); + /** + * Ensures that the charSequence is in the correct String format as the module code. + * + * @param charSequence cannot be null, cannot be empty, must be a single word. + * @return the upper case of the module code. + */ + public static String ignoreCase(String charSequence) { + String preppedCharSequence = charSequence.trim().toUpperCase(); + checkArgument(!preppedCharSequence.isEmpty(), "CharSequence parameter cannot be empty"); + checkArgument(preppedCharSequence.split("\\s+").length == 1, "CharSequence parameter should be a " + + "single word"); + return preppedCharSequence; } /** diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java index 92cd8fa605a..5a845b393d7 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/address/logic/Logic.java @@ -7,15 +7,16 @@ import seedu.address.logic.commands.CommandResult; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; +import seedu.address.model.ReadOnlyGradPad; +import seedu.address.model.module.Module; /** - * API of the Logic component + * Represents the API of the Logic component. */ public interface Logic { /** * Executes the command and returns the result. + * * @param commandText The command as entered by the user. * @return the result of the command execution. * @throws CommandException If an error occurs during command execution. @@ -24,19 +25,19 @@ public interface Logic { CommandResult execute(String commandText) throws CommandException, ParseException; /** - * Returns the AddressBook. + * Returns the GradPad. * - * @see seedu.address.model.Model#getAddressBook() + * @see seedu.address.model.Model#getGradPad() */ - ReadOnlyAddressBook getAddressBook(); + ReadOnlyGradPad getGradPad(); - /** Returns an unmodifiable view of the filtered list of persons */ - ObservableList getFilteredPersonList(); + /** Returns an unmodifiable view of the filtered list of modules */ + ObservableList getFilteredModuleList(); /** - * Returns the user prefs' address book file path. + * Returns the user prefs' GradPad file path. */ - Path getAddressBookFilePath(); + Path getGradPadFilePath(); /** * Returns the user prefs' GUI settings. diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 9d9c6d15bdc..0fcaeaeeac0 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -1,5 +1,11 @@ package seedu.address.logic; +import static seedu.address.commons.core.Messages.FILE_OPS_ERROR_MESSAGE; +import static seedu.address.commons.core.Messages.MESSAGE_CLEAR_CONFIRMATION; +import static seedu.address.commons.core.Messages.MESSAGE_CONFIRMATION_CANCEL; +import static seedu.address.commons.core.Messages.MESSAGE_DELETE_CONFIRMATION; +import static seedu.address.commons.core.Messages.MESSAGE_EMPTY_GRADPAD; + import java.io.IOException; import java.nio.file.Path; import java.util.logging.Logger; @@ -7,46 +13,99 @@ import javafx.collections.ObservableList; import seedu.address.commons.core.GuiSettings; import seedu.address.commons.core.LogsCenter; +import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.DeleteCommand; +import seedu.address.logic.commands.YesCommand; import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.logic.parser.AddressBookParser; +import seedu.address.logic.parser.GradPadParser; import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.Model; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; +import seedu.address.model.ReadOnlyGradPad; +import seedu.address.model.module.Module; import seedu.address.storage.Storage; /** * The main LogicManager of the app. */ public class LogicManager implements Logic { - public static final String FILE_OPS_ERROR_MESSAGE = "Could not save data to file: "; private final Logger logger = LogsCenter.getLogger(LogicManager.class); - private final Model model; private final Storage storage; - private final AddressBookParser addressBookParser; + private final GradPadParser gradPadParser; + + private Command stalledCommand; + private String stalledCommandText; /** * Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}. + * + * @param model {@code Model} which the LogicManager should operate on. + * @param storage the given storage to be operated on. */ public LogicManager(Model model, Storage storage) { + assert (model != null && storage != null); this.model = model; this.storage = storage; - addressBookParser = new AddressBookParser(); + gradPadParser = new GradPadParser(); + } + + private CommandResult handleStall(Command command, String commandText) throws CommandException { + if (command instanceof ClearCommand) { + assignStalledComponents(command, commandText); + return new CommandResult(MESSAGE_CLEAR_CONFIRMATION); + } else { + Module moduleToBeDeleted = ((DeleteCommand) command).getModuleToDelete(model); + assignStalledComponents(command, commandText); + return new CommandResult(MESSAGE_DELETE_CONFIRMATION + moduleToBeDeleted); + } + } + + private void assignStalledComponents(Command command, String commandText) { + stalledCommand = command; + stalledCommandText = commandText; } @Override public CommandResult execute(String commandText) throws CommandException, ParseException { logger.info("----------------[USER COMMAND][" + commandText + "]"); - + Command command; CommandResult commandResult; - Command command = addressBookParser.parseCommand(commandText); + + try { + command = gradPadParser.parseCommand(commandText); + } catch (ParseException e) { + if (stalledCommand != null) { + stalledCommand = null; + return new CommandResult(MESSAGE_CONFIRMATION_CANCEL + + String.format("\"%s\"", stalledCommandText)); + } else { + throw e; + } + } + + boolean isCancel = stalledCommand != null && !(command instanceof YesCommand); + boolean isConfirmation = stalledCommand != null && command instanceof YesCommand; + + if (isCancel) { + stalledCommand = null; + return new CommandResult(MESSAGE_CONFIRMATION_CANCEL + + String.format("\"%s\"", stalledCommandText)); + } else if (isConfirmation) { + command = stalledCommand; + stalledCommand = null; + } else if (command.requiresStall()) { + if (model.isEmpty()) { + throw new CommandException(MESSAGE_EMPTY_GRADPAD); + } + return handleStall(command, commandText); + } + commandResult = command.execute(model); try { - storage.saveAddressBook(model.getAddressBook()); + storage.saveGradPad(model.getGradPad()); } catch (IOException ioe) { throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe); } @@ -55,18 +114,18 @@ public CommandResult execute(String commandText) throws CommandException, ParseE } @Override - public ReadOnlyAddressBook getAddressBook() { - return model.getAddressBook(); + public ReadOnlyGradPad getGradPad() { + return model.getGradPad(); } @Override - public ObservableList getFilteredPersonList() { - return model.getFilteredPersonList(); + public ObservableList getFilteredModuleList() { + return model.getFilteredModuleList(); } @Override - public Path getAddressBookFilePath() { - return model.getAddressBookFilePath(); + public Path getGradPadFilePath() { + return model.getGradPadFilePath(); } @Override diff --git a/src/main/java/seedu/address/logic/ModuleInfoSearcher.java b/src/main/java/seedu/address/logic/ModuleInfoSearcher.java new file mode 100644 index 00000000000..59609d62809 --- /dev/null +++ b/src/main/java/seedu/address/logic/ModuleInfoSearcher.java @@ -0,0 +1,48 @@ +package seedu.address.logic; + +import java.util.Optional; + +import seedu.address.commons.core.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.nusmods.ModuleInfo; +import seedu.address.nusmods.NusmodsDataManager; +import seedu.address.nusmods.exceptions.NusmodsException; + +/** + * Logic for searching a module from the Computer Science curriculum. + */ +public class ModuleInfoSearcher { + private NusmodsDataManager dataManager; + + public ModuleInfoSearcher() { + dataManager = new NusmodsDataManager(); + } + + ModuleInfoSearcher(NusmodsDataManager dataManager) { + this.dataManager = dataManager; + } + + /** + * Perform search function on NUSMods using dataManager. + * + * @param moduleCode from SearchCommandParser. + * @return ModuleInfo of the module searched. + * @throws CommandException if an error occurs during the search process. + */ + public ModuleInfo searchModule(String moduleCode) throws CommandException { + ModuleInfo moduleInfo; + if (moduleCode.isEmpty()) { + throw new CommandException(Messages.MESSAGE_EMPTY_SEARCH); + } + try { + Optional moduleDetails = dataManager.getModuleInfo(moduleCode); + if (moduleDetails.isEmpty()) { + throw new CommandException(String.format(Messages.MESSAGE_FAILED_TO_FIND_MODULE, moduleCode)); + } + moduleInfo = moduleDetails.get(); + } catch (NusmodsException e) { + throw new CommandException(e.getMessage()); + } + return moduleInfo; + } +} diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index 71656d7c5c8..f478d3cc06a 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -1,61 +1,39 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.commons.core.Messages.MESSAGE_ADD_SUCCESS; +import static seedu.address.commons.core.Messages.MESSAGE_DUPLICATE_MODULE; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.module.Module; /** - * Adds a person to the address book. + * Adds a Module to the GradPad. */ public class AddCommand extends Command { - - public static final String COMMAND_WORD = "add"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. " - + "Parameters: " - + PREFIX_NAME + "NAME " - + PREFIX_PHONE + "PHONE " - + PREFIX_EMAIL + "EMAIL " - + PREFIX_ADDRESS + "ADDRESS " - + "[" + PREFIX_TAG + "TAG]...\n" - + "Example: " + COMMAND_WORD + " " - + PREFIX_NAME + "John Doe " - + PREFIX_PHONE + "98765432 " - + PREFIX_EMAIL + "johnd@example.com " - + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " - + PREFIX_TAG + "friends " - + PREFIX_TAG + "owesMoney"; - - public static final String MESSAGE_SUCCESS = "New person added: %1$s"; - public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; - - private final Person toAdd; + private final Module toAdd; /** - * Creates an AddCommand to add the specified {@code Person} + * Creates an AddCommand to add the specified {@code Module} + * + * @param module the module to be added. */ - public AddCommand(Person person) { - requireNonNull(person); - toAdd = person; + public AddCommand(Module module) { + requireNonNull(module); + toAdd = module; } @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - if (model.hasPerson(toAdd)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); + if (model.hasModule(toAdd)) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_MODULE, toAdd.getModuleCode())); } - model.addPerson(toAdd); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + model.addModule(toAdd); + return new CommandResult(String.format(MESSAGE_ADD_SUCCESS, toAdd)); } @Override diff --git a/src/main/java/seedu/address/logic/commands/CheckMcCommand.java b/src/main/java/seedu/address/logic/commands/CheckMcCommand.java new file mode 100644 index 00000000000..9ece7c69890 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/CheckMcCommand.java @@ -0,0 +1,27 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_CHECKMC_SUCCESS; + +import javafx.collections.ObservableList; +import seedu.address.model.Model; +import seedu.address.model.module.Module; + +/** + * Displays the cumulative Modular Credits of the modules in the GradPad. + */ +public class CheckMcCommand extends Command { + private ObservableList modules; + private double totalMc = 0; + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + modules = model.getGradPad().getModuleList(); + + for (Module module : modules) { + totalMc += Double.parseDouble(module.getModularCredits().toString()); + } + return new CommandResult(String.format(MESSAGE_CHECKMC_SUCCESS, totalMc)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java index 9c86b1fa6e4..afedd98d5ed 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java @@ -1,23 +1,25 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_CLEAR_SUCCESS; -import seedu.address.model.AddressBook; +import seedu.address.model.GradPad; import seedu.address.model.Model; /** - * Clears the address book. + * Clears the GradPad. */ public class ClearCommand extends Command { - public static final String COMMAND_WORD = "clear"; - public static final String MESSAGE_SUCCESS = "Address book has been cleared!"; - - @Override public CommandResult execute(Model model) { requireNonNull(model); - model.setAddressBook(new AddressBook()); - return new CommandResult(MESSAGE_SUCCESS); + model.setGradPad(new GradPad()); + return new CommandResult(MESSAGE_CLEAR_SUCCESS); + } + + @Override + public boolean requiresStall() { + return true; } } diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/address/logic/commands/Command.java index 64f18992160..4a898e4bf08 100644 --- a/src/main/java/seedu/address/logic/commands/Command.java +++ b/src/main/java/seedu/address/logic/commands/Command.java @@ -17,4 +17,12 @@ public abstract class Command { */ public abstract CommandResult execute(Model model) throws CommandException; + /** + * Checks if the command requires confirmation from the user and needs to be stalled. + * + * @return generally returns false as most commands do not require confirmation from the user. + */ + public boolean requiresStall() { + return false; + } } diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java index 92f900b7916..85b1a399535 100644 --- a/src/main/java/seedu/address/logic/commands/CommandResult.java +++ b/src/main/java/seedu/address/logic/commands/CommandResult.java @@ -8,42 +8,38 @@ * Represents the result of a command execution. */ public class CommandResult { - private final String feedbackToUser; - /** Help information should be shown to the user. */ - private final boolean showHelp; - /** The application should exit. */ - private final boolean exit; + private final boolean isExit; /** * Constructs a {@code CommandResult} with the specified fields. + * + * @param feedbackToUser the feedback to the user. + * @param isExit the boolean variable to indicate whether the app should exit. */ - public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) { + public CommandResult(String feedbackToUser, boolean isExit) { this.feedbackToUser = requireNonNull(feedbackToUser); - this.showHelp = showHelp; - this.exit = exit; + this.isExit = isExit; } /** * Constructs a {@code CommandResult} with the specified {@code feedbackToUser}, * and other fields set to their default value. + * + * @param feedbackToUser the feedback to the user. */ public CommandResult(String feedbackToUser) { - this(feedbackToUser, false, false); + this(feedbackToUser, false); } public String getFeedbackToUser() { return feedbackToUser; } - public boolean isShowHelp() { - return showHelp; - } - public boolean isExit() { - return exit; + return isExit; } @Override @@ -59,13 +55,11 @@ public boolean equals(Object other) { CommandResult otherCommandResult = (CommandResult) other; return feedbackToUser.equals(otherCommandResult.feedbackToUser) - && showHelp == otherCommandResult.showHelp - && exit == otherCommandResult.exit; + && isExit == otherCommandResult.isExit; } @Override public int hashCode() { - return Objects.hash(feedbackToUser, showHelp, exit); + return Objects.hash(feedbackToUser, isExit); } - } diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java index 02fd256acba..b6140c89727 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java @@ -1,53 +1,68 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_DELETE_SUCCESS; import java.util.List; +import java.util.Optional; import seedu.address.commons.core.Messages; -import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Person; +import seedu.address.model.module.Module; +import seedu.address.model.module.ModuleCode; /** - * Deletes a person identified using it's displayed index from the address book. + * Deletes a Module identified using a Module's ModuleCode. + * This delete operation requires a confirmation to be given. */ public class DeleteCommand extends Command { + private final ModuleCode code; - public static final String COMMAND_WORD = "delete"; - - public static final String MESSAGE_USAGE = COMMAND_WORD - + ": Deletes the person identified by the index number used in the displayed person list.\n" - + "Parameters: INDEX (must be a positive integer)\n" - + "Example: " + COMMAND_WORD + " 1"; - - public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; + /** + * Creates a DeleteCommand to delete the module with the specified {@code ModuleCode} + * + * @param code + */ + public DeleteCommand(ModuleCode code) { + this.code = code; + } - private final Index targetIndex; + /** + * Retrieves the module to be deleted. + * + * @param model the Model which the command operates on. + * @return the module to be deleted. + * @throws CommandException if the module cannot be found in Completed Modules. + */ + public Module getModuleToDelete(Model model) throws CommandException { + List modules = model.getGradPad().getModuleList(); - public DeleteCommand(Index targetIndex) { - this.targetIndex = targetIndex; + Optional moduleToDelete = modules.stream() + .filter(module -> module.getModuleCode().equals(code)).findFirst(); + if (moduleToDelete.isEmpty()) { + throw new CommandException(String.format(Messages.MESSAGE_INVALID_MODULE, code.toString())); + } + return moduleToDelete.get(); } @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); - - if (targetIndex.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); - } - - Person personToDelete = lastShownList.get(targetIndex.getZeroBased()); - model.deletePerson(personToDelete); - return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete)); + Module moduleToDelete = getModuleToDelete(model); + model.deleteModule(moduleToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_SUCCESS, moduleToDelete)); } @Override public boolean equals(Object other) { return other == this // short circuit if same object || (other instanceof DeleteCommand // instanceof handles nulls - && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check + && code.equals(((DeleteCommand) other).code)); // state check + } + + @Override + public boolean requiresStall() { + return true; } } diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 7e36114902f..c15ea482e04 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -1,12 +1,11 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static seedu.address.commons.core.Messages.MESSAGE_ALL_EDIT_FIELDS_SAME; +import static seedu.address.commons.core.Messages.MESSAGE_DUPLICATE_MODULE; +import static seedu.address.commons.core.Messages.MESSAGE_EDIT_SUCCESS; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_MODULE; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_MODULES; import java.util.Collections; import java.util.HashSet; @@ -14,92 +13,81 @@ import java.util.Optional; import java.util.Set; -import seedu.address.commons.core.Messages; -import seedu.address.commons.core.index.Index; import seedu.address.commons.util.CollectionUtil; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; +import seedu.address.model.module.ModularCredits; +import seedu.address.model.module.Module; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTitle; import seedu.address.model.tag.Tag; /** - * Edits the details of an existing person in the address book. + * Edits the details of an existing module in the GradPad. */ public class EditCommand extends Command { - - public static final String COMMAND_WORD = "edit"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified " - + "by the index number used in the displayed person list. " - + "Existing values will be overwritten by the input values.\n" - + "Parameters: INDEX (must be a positive integer) " - + "[" + PREFIX_NAME + "NAME] " - + "[" + PREFIX_PHONE + "PHONE] " - + "[" + PREFIX_EMAIL + "EMAIL] " - + "[" + PREFIX_ADDRESS + "ADDRESS] " - + "[" + PREFIX_TAG + "TAG]...\n" - + "Example: " + COMMAND_WORD + " 1 " - + PREFIX_PHONE + "91234567 " - + PREFIX_EMAIL + "johndoe@example.com"; - - public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s"; - public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; - public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book."; - - private final Index index; - private final EditPersonDescriptor editPersonDescriptor; + private final ModuleCode code; + private final EditModuleDescriptor editModuleDescriptor; /** - * @param index of the person in the filtered person list to edit - * @param editPersonDescriptor details to edit the person with + * Creates an EditCommand to edit the module with the specified {@code EditModuleDescriptor}. + * + * @param code the module code of the module in GradPad to edit. + * @param editModuleDescriptor the descriptor which contains details to edit the module with. */ - public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) { - requireNonNull(index); - requireNonNull(editPersonDescriptor); + public EditCommand(ModuleCode code, EditModuleDescriptor editModuleDescriptor) { + requireNonNull(code); + requireNonNull(editModuleDescriptor); - this.index = index; - this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor); + this.code = code; + this.editModuleDescriptor = new EditModuleDescriptor(editModuleDescriptor); } @Override public CommandResult execute(Model model) throws CommandException { requireNonNull(model); - List lastShownList = model.getFilteredPersonList(); + List modules = model.getGradPad().getModuleList(); - if (index.getZeroBased() >= lastShownList.size()) { - throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + Optional moduleToEdit = modules.stream() + .filter(x -> x.getModuleCode().equals(code)).findFirst(); + if (moduleToEdit.isEmpty()) { + throw new CommandException(String.format(MESSAGE_INVALID_MODULE, code.toString())); } - Person personToEdit = lastShownList.get(index.getZeroBased()); - Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); + Module editedModule = createEditedModule(moduleToEdit.get(), editModuleDescriptor); + + if (moduleToEdit.get().equals(editedModule)) { + throw new CommandException(MESSAGE_ALL_EDIT_FIELDS_SAME); + } - if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { - throw new CommandException(MESSAGE_DUPLICATE_PERSON); + if (!moduleToEdit.get().isSameModule(editedModule) && model.hasModule(editedModule)) { + throw new CommandException(String.format(MESSAGE_DUPLICATE_MODULE, editedModule.getModuleCode())); } - model.setPerson(personToEdit, editedPerson); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson)); + model.setModule(moduleToEdit.get(), editedModule); + model.updateFilteredModuleList(PREDICATE_SHOW_ALL_MODULES); + return new CommandResult(String.format(MESSAGE_EDIT_SUCCESS, moduleToEdit.get(), editedModule)); } /** - * Creates and returns a {@code Person} with the details of {@code personToEdit} - * edited with {@code editPersonDescriptor}. + * Creates and returns a {@code Module} with the details of {@code moduleToEdit} + * edited with {@code editModuleDescriptor}. + * + * @param moduleToEdit the module to edit. + * @param editModuleDescriptor + * @return */ - private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) { - assert personToEdit != null; + private static Module createEditedModule(Module moduleToEdit, EditModuleDescriptor editModuleDescriptor) { + assert moduleToEdit != null; - Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName()); - Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone()); - Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail()); - Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress()); - Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); + ModuleCode updatedCode = editModuleDescriptor.getModuleCode().orElse(moduleToEdit.getModuleCode()); + ModuleTitle updatedTitle = editModuleDescriptor.getModuleTitle() + .orElse(moduleToEdit.getModuleTitle()); + ModularCredits updatedCredits = editModuleDescriptor.getModularCredits() + .orElse(moduleToEdit.getModularCredits()); + Set updatedTags = editModuleDescriptor.getTags().orElse(moduleToEdit.getTags()); - return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags); + return new Module(updatedCode, updatedTitle, updatedCredits, updatedTags); } @Override @@ -116,32 +104,30 @@ public boolean equals(Object other) { // state check EditCommand e = (EditCommand) other; - return index.equals(e.index) - && editPersonDescriptor.equals(e.editPersonDescriptor); + return code.equals(e.code) + && editModuleDescriptor.equals(e.editModuleDescriptor); } /** - * Stores the details to edit the person with. Each non-empty field value will replace the - * corresponding field value of the person. + * Stores the details to edit the module with. Each non-empty field value will replace the + * corresponding field value of the module. */ - public static class EditPersonDescriptor { - private Name name; - private Phone phone; - private Email email; - private Address address; + public static class EditModuleDescriptor { + private ModuleCode code; + private ModuleTitle title; + private ModularCredits credits; private Set tags; - public EditPersonDescriptor() {} + public EditModuleDescriptor() {} /** * Copy constructor. * A defensive copy of {@code tags} is used internally. */ - public EditPersonDescriptor(EditPersonDescriptor toCopy) { - setName(toCopy.name); - setPhone(toCopy.phone); - setEmail(toCopy.email); - setAddress(toCopy.address); + public EditModuleDescriptor(EditModuleDescriptor toCopy) { + setModuleCode(toCopy.code); + setModuleTitle(toCopy.title); + setModularCredits(toCopy.credits); setTags(toCopy.tags); } @@ -149,39 +135,31 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { * Returns true if at least one field is edited. */ public boolean isAnyFieldEdited() { - return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); - } - - public void setName(Name name) { - this.name = name; - } - - public Optional getName() { - return Optional.ofNullable(name); + return CollectionUtil.isAnyNonNull(code, title, credits, tags); } - public void setPhone(Phone phone) { - this.phone = phone; + public void setModuleCode(ModuleCode code) { + this.code = code; } - public Optional getPhone() { - return Optional.ofNullable(phone); + public Optional getModuleCode() { + return Optional.ofNullable(code); } - public void setEmail(Email email) { - this.email = email; + public void setModuleTitle(ModuleTitle title) { + this.title = title; } - public Optional getEmail() { - return Optional.ofNullable(email); + public Optional getModuleTitle() { + return Optional.ofNullable(title); } - public void setAddress(Address address) { - this.address = address; + public void setModularCredits(ModularCredits credits) { + this.credits = credits; } - public Optional
getAddress() { - return Optional.ofNullable(address); + public Optional getModularCredits() { + return Optional.ofNullable(credits); } /** @@ -209,18 +187,17 @@ public boolean equals(Object other) { } // instanceof handles nulls - if (!(other instanceof EditPersonDescriptor)) { + if (!(other instanceof EditModuleDescriptor)) { return false; } // state check - EditPersonDescriptor e = (EditPersonDescriptor) other; + EditModuleDescriptor e = (EditModuleDescriptor) other; - return getName().equals(e.getName()) - && getPhone().equals(e.getPhone()) - && getEmail().equals(e.getEmail()) - && getAddress().equals(e.getAddress()) - && getTags().equals(e.getTags()); + return getModuleCode().equals(e.getModuleCode()) + && getModuleTitle().equals(e.getModuleTitle()) + && getModularCredits().equals(e.getModularCredits()) + && getTags().equals(e.getTags()); } } } diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java index 3dd85a8ba90..d17b3ca90f4 100644 --- a/src/main/java/seedu/address/logic/commands/ExitCommand.java +++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java @@ -1,5 +1,7 @@ package seedu.address.logic.commands; +import static seedu.address.commons.core.Messages.MESSAGE_EXIT_ACKNOWLEDGEMENT; + import seedu.address.model.Model; /** @@ -7,13 +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 ..."; - @Override public CommandResult execute(Model model) { - return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true); + return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, true); } - } diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java index d6b19b0a0de..172d0262bcc 100644 --- a/src/main/java/seedu/address/logic/commands/FindCommand.java +++ b/src/main/java/seedu/address/logic/commands/FindCommand.java @@ -2,35 +2,35 @@ import static java.util.Objects.requireNonNull; +import java.util.function.Predicate; + import seedu.address.commons.core.Messages; import seedu.address.model.Model; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.module.Module; /** - * Finds and lists all persons in address book whose name contains any of the argument keywords. + * Finds and lists all modules in GradPad whose name or tag contains any of the argument keywords. * Keyword matching is case insensitive. */ public class FindCommand extends Command { - - public static final String COMMAND_WORD = "find"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of " - + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n" - + "Parameters: KEYWORD [MORE_KEYWORDS]...\n" - + "Example: " + COMMAND_WORD + " alice bob charlie"; - - private final NameContainsKeywordsPredicate predicate; - - public FindCommand(NameContainsKeywordsPredicate predicate) { + private final Predicate predicate; + + /** + * Creates a FindCommand to filter module(s) based on the specified predicate. + * + * @param predicate the predicate used to filter relevant module(s). + */ + public FindCommand(Predicate predicate) { + assert(predicate != null); this.predicate = predicate; } @Override public CommandResult execute(Model model) { requireNonNull(model); - model.updateFilteredPersonList(predicate); + model.updateFilteredModuleList(predicate); return new CommandResult( - String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size())); + String.format(Messages.MESSAGE_MODULES_FOUND_OVERVIEW, model.getFilteredModuleList().size())); } @Override diff --git a/src/main/java/seedu/address/logic/commands/ForceClearCommand.java b/src/main/java/seedu/address/logic/commands/ForceClearCommand.java new file mode 100644 index 00000000000..cfe5b2521d8 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ForceClearCommand.java @@ -0,0 +1,12 @@ +package seedu.address.logic.commands; + +/** + * Force-clears the GradPad. + */ +public class ForceClearCommand extends ClearCommand { + + @Override + public boolean requiresStall() { + return false; + } +} diff --git a/src/main/java/seedu/address/logic/commands/ForceDeleteCommand.java b/src/main/java/seedu/address/logic/commands/ForceDeleteCommand.java new file mode 100644 index 00000000000..f2e434d9a7c --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ForceDeleteCommand.java @@ -0,0 +1,23 @@ +package seedu.address.logic.commands; + +import seedu.address.model.module.ModuleCode; + +/** + * Force-deletes a Module identified using a Module's ModuleCode. + */ +public class ForceDeleteCommand extends DeleteCommand { + + /** + * Creates a ForceDeleteCommand to force delete the module with the specified {@code ModuleCode} + * + * @param code the module code of the module to be deleted. + */ + public ForceDeleteCommand(ModuleCode code) { + super(code); + } + + @Override + public boolean requiresStall() { + return false; + } +} diff --git a/src/main/java/seedu/address/logic/commands/GemCommand.java b/src/main/java/seedu/address/logic/commands/GemCommand.java new file mode 100644 index 00000000000..c3d19f2fe2e --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/GemCommand.java @@ -0,0 +1,150 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.LINE; +import static seedu.address.commons.core.Messages.MESSAGE_GEM_FAILURE; +import static seedu.address.commons.core.Messages.MESSAGE_GEM_SUCCESS; +import static seedu.address.storage.GemCommandPaths.GEH_SEM1_PATH; +import static seedu.address.storage.GemCommandPaths.GEH_SEM2_PATH; +import static seedu.address.storage.GemCommandPaths.GEQ_PATH; +import static seedu.address.storage.GemCommandPaths.GER_PATH; +import static seedu.address.storage.GemCommandPaths.GES_SEM1_PATH; +import static seedu.address.storage.GemCommandPaths.GES_SEM2_PATH; +import static seedu.address.storage.GemCommandPaths.GET_SEM1_PATH; +import static seedu.address.storage.GemCommandPaths.GET_SEM2_PATH; + +import java.io.IOException; + +import javafx.collections.ObservableList; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.Model; +import seedu.address.model.module.Module; +import seedu.address.storage.GemCommandStorage; + +public class GemCommand extends Command { + private GemCommandStorage sem1Storage; + private GemCommandStorage sem2Storage; + private String compiledModules; + + /** + * Retrieves the attribute sem1Storage of a GemCommand object. + * + * @return storage attribute of type GemCommandStorage. + */ + public GemCommandStorage getSem1Storage() { + return sem1Storage; + } + + /** + * Retrieves the attribute sem2Storage of a GemCommand object. + * + * @return storage attribute of type GemCommandStorage. + */ + public GemCommandStorage getSem2Storage() { + return sem2Storage; + } + + /** + * Loads the sem1Storage attribute with Semester 1 GE Modules by using + * the various set() methods from the GemCommandStorage class. + * + * @throws IOException when the path in invalid. + * @throws IllegalValueException when the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setSem1Storage() throws IOException, IllegalValueException { + sem1Storage = new GemCommandStorage(); + sem1Storage.setGehModules(GEH_SEM1_PATH); + sem1Storage.setGeqModules(GEQ_PATH); + sem1Storage.setGerModules(GER_PATH); + sem1Storage.setGesModules(GES_SEM1_PATH); + sem1Storage.setGetModules(GET_SEM1_PATH); + } + + /** + * Loads the sem2Storage attribute with Semester 2 GE Modules by using + * the various set() methods from the GemCommandStorage class. + * + * @throws IOException when the path in invalid. + * @throws IllegalValueException when the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setSem2Storage() throws IOException, IllegalValueException { + sem2Storage = new GemCommandStorage(); + sem2Storage.setGehModules(GEH_SEM2_PATH); + sem2Storage.setGeqModules(GEQ_PATH); + sem2Storage.setGerModules(GER_PATH); + sem2Storage.setGesModules(GES_SEM2_PATH); + sem2Storage.setGetModules(GET_SEM2_PATH); + } + + /** + * Sets up the all the GE modules in the sem1Storage and sem2Storage and displays them + * with the CommandResult object. + * + * @param model {@code Model} which the command should operate on. + * @return a CommandResult displaying all the available GE modules. + */ + @Override + public CommandResult execute(Model model) { + try { + requireNonNull(model); + setSem1Storage(); + setSem2Storage(); + String modulesToAdd = "\n\nSemester 1:" + "\n\n"; + setCompiledModules(sem1Storage, model); + modulesToAdd += compiledModules; + modulesToAdd += "\n\n" + LINE + "Semester 2:" + "\n\n"; + setCompiledModules(sem2Storage, model); + modulesToAdd += compiledModules; + return new CommandResult(MESSAGE_GEM_SUCCESS + modulesToAdd); + } catch (IOException | IllegalValueException e) { + return new CommandResult(MESSAGE_GEM_FAILURE); + } + } + + /** + * Takes a List of Modules and extracts out their Module Code and Modular Credits. + * + * @param modules List of Modules. + * @param model {@code Model} which the command should operate on. + * @return String of Module Codes and Modular Credits. + */ + public StringBuilder moduleExtractor(ObservableList modules, Model model) { + assert modules != null; + StringBuilder modulesToAdd = new StringBuilder(); + for (Module module : modules) { + if (!model.hasModule(module)) { + String moduleToAdd = module.getModuleCode() + "\t" + module.getModuleTitle() + + " (" + module.getModularCredits() + " MCs)"; + modulesToAdd.append("\n").append(moduleToAdd); + } + } + return modulesToAdd; + } + + /** + * Loads the compiledModules attribute with all the relevant GE modules in String form. + * + * @param storage Contains list of GE modules. + * @param model {@code Model} which the command should operate on. + */ + public void setCompiledModules(GemCommandStorage storage, Model model) { + compiledModules = ""; + compiledModules += "Human Cultures\n" + moduleExtractor(storage.getGehModules(), model) + "\n\n"; + compiledModules += "Thinking and Expression\n" + moduleExtractor(storage.getGetModules(), model) + + "\n\n"; + compiledModules += "Singapore Studies\n" + moduleExtractor(storage.getGesModules(), model) + "\n\n"; + compiledModules += "Asking Questions\n" + moduleExtractor(storage.getGeqModules(), model) + "\n\n"; + compiledModules += "Quantitative Reasoning\n" + moduleExtractor(storage.getGerModules(), model); + } + + /** + * Returns compiledModules attribute of GemCommandStorage object. + * + * @return compiledModules attribute of type String. + */ + public String getCompiledModules() { + return compiledModules; + } +} diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java index bf824f91bd0..624c62bd0ca 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java @@ -1,21 +1,16 @@ package seedu.address.logic.commands; +import static seedu.address.commons.core.Messages.SHOWING_HELP_MESSAGE; + import seedu.address.model.Model; /** - * Format full help instructions for every command for display. + * Formats full help instructions for every command for display. */ public class HelpCommand extends Command { - public static final String COMMAND_WORD = "help"; - - public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" - + "Example: " + COMMAND_WORD; - - public static final String SHOWING_HELP_MESSAGE = "Opened help window."; - @Override public CommandResult execute(Model model) { - return new CommandResult(SHOWING_HELP_MESSAGE, true, false); + return new CommandResult(SHOWING_HELP_MESSAGE, false); } } diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java index 84be6ad2596..fd67fbf440e 100644 --- a/src/main/java/seedu/address/logic/commands/ListCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListCommand.java @@ -1,24 +1,20 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; +import static seedu.address.commons.core.Messages.MESSAGE_LIST_SUCCESS; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_MODULES; import seedu.address.model.Model; /** - * Lists all persons in the address book to the user. + * Lists all modules in GradPad to the user. */ public class ListCommand extends Command { - public static final String COMMAND_WORD = "list"; - - public static final String MESSAGE_SUCCESS = "Listed all persons"; - - @Override public CommandResult execute(Model model) { requireNonNull(model); - model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(MESSAGE_SUCCESS); + model.updateFilteredModuleList(PREDICATE_SHOW_ALL_MODULES); + return new CommandResult(MESSAGE_LIST_SUCCESS); } } diff --git a/src/main/java/seedu/address/logic/commands/RequiredCommand.java b/src/main/java/seedu/address/logic/commands/RequiredCommand.java new file mode 100644 index 00000000000..4fa503a2611 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/RequiredCommand.java @@ -0,0 +1,285 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.storage.RequiredCommandMessages.FOUNDATION_PATH; +import static seedu.address.storage.RequiredCommandMessages.INTERNSHIP_PATH; +import static seedu.address.storage.RequiredCommandMessages.ITPROF_PATH; +import static seedu.address.storage.RequiredCommandMessages.MATH_PATH; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_FAILURE; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_FAILURE_GE_1; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_FAILURE_GE_2; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_FOUNDATION; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_INTERN_1; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_INTERN_2; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_ITPROF; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_MATH; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SCIENCE; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SUCCESS_FOUNDATION; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SUCCESS_GE; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SUCCESS_INTERN; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SUCCESS_ITPROF; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SUCCESS_MATH; +import static seedu.address.storage.RequiredCommandMessages.MESSAGE_SUCCESS_SCIENCE; +import static seedu.address.storage.RequiredCommandMessages.PRECLUSION_PATH; +import static seedu.address.storage.RequiredCommandMessages.SCIENCE_PATH; + +import java.io.IOException; +import java.util.Map; + +import javafx.collections.ObservableList; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.Model; +import seedu.address.model.module.Module; +import seedu.address.storage.RequiredCommandStorage; + +public class RequiredCommand extends Command { + private ObservableList currentModules; + private String leftOverModules = ""; + private RequiredCommandStorage storage; + + /** + * Retrieves the leftOverModules attribute of a RequiredCommand object. + * + * @return leftOverModules of type String. + */ + public String getLeftOverModules() { + return leftOverModules; + } + + /** + * Retrieves the attribute storage of a RequiredCommand object. + * + * @return storage attribute of type RequiredCommandStorage. + */ + public RequiredCommandStorage getStorage() { + return storage; + } + + /** + * Sets up the storage attribute with all the relevant modules from various fields. + * + * @throws IOException when path is invalid. + * @throws IllegalValueException when the data from the JSON file violates some constraints. + */ + public void setStorage() throws IOException, IllegalValueException { + storage = new RequiredCommandStorage(); + storage.setRequiredFoundation(FOUNDATION_PATH); + storage.setRequiredITprof(ITPROF_PATH); + storage.setRequiredMath(MATH_PATH); + storage.setRequiredScience(SCIENCE_PATH); + storage.setRequiredInternship(INTERNSHIP_PATH); + storage.setPreclusionMap(PRECLUSION_PATH); + } + + /** + * Retrieves the currentModules attribute of an Required Command object. + * + * @return currentModules attribute of type ObservableList. + */ + public ObservableList getCurrentModules() { + return currentModules; + } + + /** + * Sets the argument modules as the attribute currentModules. + * + * @param modules target argument of type ObservableList. + */ + public void setCurrentModules(ObservableList modules) { + currentModules = modules; + } + + /** + * Checks if a Module already exists in a given Module List. + * + * @param module Module that you wish to check. + * @param modules Module List that you wish to check against. + * @return True if the module already exists, false otherwise. + */ + public boolean doesModuleAlreadyExist(Module module, ObservableList modules) { + for (Module mod : modules) { + if (module.isSameModule(mod)) { + return true; + } + } + return false; + } + + /** + * Checks if a Module is a valid preclusion. + * + * @param module Module to check. + * @param modules Module list to check against. + * @return True if module is a preclusion, false otherwise. + */ + public boolean isModuleAPreclusion(Module module, ObservableList modules) { + Map preclusionMap = storage.getPreclusionMap(); + String modToCheckAgainst = module.getModuleCode().toString(); + if (preclusionMap.containsKey(modToCheckAgainst)) { + String modulePreclusion = preclusionMap.get(modToCheckAgainst); + for (Module mod : modules) { + String currentModName = mod.getModuleCode().toString(); + if (modulePreclusion.contains(currentModName)) { + return true; + } + } + } + return false; + } + + /** + * Cross references the user's current list of Modules against the given + * modules argument and marks out any undone Modules. Displays a successMessage + * if all modules are done, and a failMessage if there are left over modules. + * + * @param modules List of Modules of a certain category (Eg. Foundation, IT Professsionalism). + * @param failMessage Fail message for particular category of Modules. + * @param successMessage Success message for particular category of Modules. + */ + public void compareModules(ObservableList modules, String failMessage, String successMessage) { + boolean areModulesCleared = true; + StringBuilder modulesToAdd = new StringBuilder(); + for (Module module : modules) { + if (!doesModuleAlreadyExist(module, currentModules) + && !isModuleAPreclusion(module, currentModules)) { + String moduleToAdd = module.getModuleCode() + "\t" + module.getModuleTitle() + + " (" + module.getModularCredits() + " MCs)"; + modulesToAdd.append("\n").append(moduleToAdd); + areModulesCleared = false; + } + } if (areModulesCleared) { + leftOverModules += successMessage + "\n"; + } else { + leftOverModules += failMessage + modulesToAdd + "\n"; + } + leftOverModules += "\n"; + } + + /** + * Cross references the user's current list of Modules and marks out + * any undone Science Modules. + * + * @param requiredScience List of required Science Modules. + */ + public void compareScience(ObservableList requiredScience) { + boolean isScienceCleared = false; + for (Module module : requiredScience) { + if (doesModuleAlreadyExist(module, currentModules)) { + leftOverModules += MESSAGE_SUCCESS_SCIENCE + "\n"; + isScienceCleared = true; + break; + } + } if (!isScienceCleared) { + leftOverModules += MESSAGE_SCIENCE + "\n"; + } + leftOverModules += "\n"; + } + + /** + * Cross references the user's current list of Modules and marks out + * any undone Internship Modules. Also calculates current MC score + * achieved from Internship Modules. + * + * @param requiredInternship List of required Internship Modules. + */ + public void compareInternship(ObservableList requiredInternship) { + int modularScore = 0; + StringBuilder leftOverInternship = new StringBuilder(); + for (Module module : requiredInternship) { + if (doesModuleAlreadyExist(module, currentModules)) { + int modularCredits = Integer.parseInt(module.getModularCredits().toString()); + modularScore += modularCredits; + } else { + String moduleToAdd = module.getModuleCode() + "\t" + module.getModuleTitle() + + " (" + module.getModularCredits() + " MCs)"; + leftOverInternship.append("\n").append(moduleToAdd); + } + } if (modularScore < 12) { + String modScore = " You are currently at " + modularScore + " MCs. "; + leftOverModules += MESSAGE_INTERN_1 + modScore + MESSAGE_INTERN_2 + leftOverInternship; + } else { + leftOverModules += MESSAGE_SUCCESS_INTERN; + } + } + + /** + * Checks if particular GE field is cleared in the current GradPad. + * + * @param ge The GE field that you wish to check (Eg. 'GEQ' or 'GEH'). + * @return True if the GE field is cleared, false otherwise. + */ + public boolean isGePresent(String ge) { + for (Module module : currentModules) { + String moduleCode = module.getModuleCode().toString(); + if (moduleCode.startsWith(ge)) { + return true; + } + } + return false; + } + + /** + * Checks which GE fields are not clear in the current GradPad and + * adds to the attribute leftOverModules if that particular GE field + * has not been cleared. + */ + public void compareAllGEs() { + String uncompletedGEs = "\n"; + boolean allGEsCleared = true; + if (!isGePresent("GEH")) { + uncompletedGEs += "GEH" + "\n"; + allGEsCleared = false; + } + if (!isGePresent("GEQ")) { + uncompletedGEs += "GEQ" + "\n"; + allGEsCleared = false; + } + if (!isGePresent("GER")) { + uncompletedGEs += "GER" + "\n"; + allGEsCleared = false; + } + if (!isGePresent("GES")) { + uncompletedGEs += "GES" + "\n"; + allGEsCleared = false; + } + if (!isGePresent("GET")) { + uncompletedGEs += "GET" + "\n"; + allGEsCleared = false; + } + if (allGEsCleared) { + leftOverModules += MESSAGE_SUCCESS_GE + "\n"; + } else { + leftOverModules += MESSAGE_FAILURE_GE_1 + uncompletedGEs + MESSAGE_FAILURE_GE_2 + "\n"; + } + leftOverModules += "\n"; + } + + /** + * Sets up the reference modules and the current modules in gradPad and compares all the modules. + * + * @param model {@code Model} which the command should operate on. + * @return a CommandResult displaying all the undone modules. + */ + @Override + public CommandResult execute(Model model) { + try { + requireNonNull(model); + currentModules = model.getGradPad().getModuleList(); + setStorage(); + ObservableList requiredFoundation = storage.getRequiredFoundation(); + ObservableList requiredITprof = storage.getRequiredITprof(); + ObservableList requiredMath = storage.getRequiredMath(); + ObservableList requiredScience = storage.getRequiredScience(); + ObservableList requiredInternship = storage.getRequiredInternship(); + compareAllGEs(); + compareModules(requiredFoundation, MESSAGE_FOUNDATION, MESSAGE_SUCCESS_FOUNDATION); + compareModules(requiredITprof, MESSAGE_ITPROF, MESSAGE_SUCCESS_ITPROF); + compareModules(requiredMath, MESSAGE_MATH, MESSAGE_SUCCESS_MATH); + compareScience(requiredScience); + compareInternship(requiredInternship); + return new CommandResult(leftOverModules); + } catch (IOException | IllegalValueException e) { + return new CommandResult(MESSAGE_FAILURE); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/ScienceCommand.java b/src/main/java/seedu/address/logic/commands/ScienceCommand.java new file mode 100644 index 00000000000..f240b349b2b --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/ScienceCommand.java @@ -0,0 +1,68 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_FAILURE_SCIENCE; +import static seedu.address.commons.core.Messages.MESSAGE_SCIENCE_SUCCESS; +import static seedu.address.storage.RequiredCommandMessages.SCIENCE_PATH; + +import java.io.IOException; + +import javafx.collections.ObservableList; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.Model; +import seedu.address.model.module.Module; +import seedu.address.storage.RequiredCommandStorage; + +public class ScienceCommand extends Command { + private ObservableList scienceModules; + + /** + * Returns the scienceModules attribute of a given ScienceCommand object. + * + * @return scienceModules attribute of type ObservableList. + */ + public ObservableList getScienceModules() { + return scienceModules; + } + + /** + * Loads the scienceModules attribute with Science Modules by using + * the setRequiredScience() method from the RequiredCommandStorage class. + * + * @param path Path of the Science Modules file. + * @throws IOException When the path in invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setScienceModules(String path) throws IOException, IllegalValueException { + RequiredCommandStorage storage = new RequiredCommandStorage(); + storage.setRequiredScience(path); + scienceModules = storage.getRequiredScience(); + } + + /** + * Goes through the scienceModules attribute and parses all Science Modules, to be read by the user. + * + * @param model {@code Model} which the command should operate on. + * @return CommandResult Object with the relevant Science Modules or Failure Message if modules + * are absent. + */ + @Override + public CommandResult execute(Model model) { + try { + requireNonNull(model); + setScienceModules(SCIENCE_PATH); + StringBuilder modulesToAdd = new StringBuilder(); + for (Module module : scienceModules) { + if (!model.hasModule(module)) { + String moduleToAdd = module.getModuleCode() + "\t" + module.getModuleTitle() + + " (" + module.getModularCredits() + " MCs)"; + modulesToAdd.append("\n").append(moduleToAdd); + } + } + return new CommandResult(MESSAGE_SCIENCE_SUCCESS + "\n" + modulesToAdd); + } catch (IOException | IllegalValueException e) { + return new CommandResult(MESSAGE_FAILURE_SCIENCE); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/SearchCommand.java b/src/main/java/seedu/address/logic/commands/SearchCommand.java new file mode 100644 index 00000000000..dceef7156d6 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/SearchCommand.java @@ -0,0 +1,54 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_SEARCH_SUCCESS; + +import java.util.Optional; + +import seedu.address.logic.ModuleInfoSearcher; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.module.ModuleCode; +import seedu.address.nusmods.ModuleInfo; + +/** + * Search for a module to display its module details. + * Module Code matching is case insensitive. + */ +public class SearchCommand extends Command { + private final ModuleCode moduleCode; + + /** + * Creates a SearchCommand to search for a module from the Computer Science + * curriculum {@code Module}. + * + * @param moduleCode the module code of the module to be searched. + */ + public SearchCommand(ModuleCode moduleCode) { + requireNonNull(moduleCode); + this.moduleCode = moduleCode; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + ModuleInfoSearcher moduleInfoSearcher = new ModuleInfoSearcher(); + ModuleInfo searchResult = moduleInfoSearcher.searchModule(moduleCode.moduleCode); + + // preclusions and prerequisites could be null + String preclusion = Optional.ofNullable(searchResult.getPreclusion()).orElse("None"); + String prerequisite = Optional.ofNullable(searchResult.getPrerequisite()).orElse("None"); + + String searchDisplay = String.format(MESSAGE_SEARCH_SUCCESS, searchResult.getModuleCode(), + searchResult.getModuleCredit(), searchResult.getTitle(), + searchResult.getDescription(), preclusion, prerequisite, searchResult.getSemesters()); + return new CommandResult(searchDisplay); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof SearchCommand // instanceof handles nulls + && moduleCode.equals(((SearchCommand) other).moduleCode)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/TagsCommand.java b/src/main/java/seedu/address/logic/commands/TagsCommand.java new file mode 100644 index 00000000000..c8e3b7d6193 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/TagsCommand.java @@ -0,0 +1,28 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_NO_TAGS; +import static seedu.address.commons.core.Messages.MESSAGE_TAGS_SUCCESS; + +import java.util.List; + +import seedu.address.model.Model; + +/** + * Lists all tags in GradPad. + */ +public class TagsCommand extends Command { + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + + List tagNames = model.getGradPad().getTags().getTagNames(); + if (tagNames.isEmpty()) { + return new CommandResult(MESSAGE_NO_TAGS); + } + + String tags = String.join("\n", tagNames); + return new CommandResult(MESSAGE_TAGS_SUCCESS + tags); + } +} diff --git a/src/main/java/seedu/address/logic/commands/YesCommand.java b/src/main/java/seedu/address/logic/commands/YesCommand.java new file mode 100644 index 00000000000..1f650d007ad --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/YesCommand.java @@ -0,0 +1,16 @@ +package seedu.address.logic.commands; + +import static seedu.address.commons.core.Messages.MESSAGE_NO_CONFIRMATION; + +import seedu.address.model.Model; + +/** + * Represents a confirmation. + */ +public class YesCommand extends Command { + + @Override + public CommandResult execute(Model model) { + return new CommandResult(MESSAGE_NO_CONFIRMATION); + } +} diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java index a16bd14f2cd..2c400e7a94f 100644 --- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java +++ b/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java @@ -10,6 +10,9 @@ public CommandException(String message) { /** * Constructs a new {@code CommandException} with the specified detail {@code message} and {@code cause}. + * + * @param message the specified message. + * @param cause the specified cause. */ public CommandException(String message, Throwable cause) { super(message, cause); diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java index 3b8bfa035e8..462ea8dccd8 100644 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java @@ -1,60 +1,77 @@ package seedu.address.logic.parser; +import static seedu.address.commons.core.Messages.MESSAGE_ADD_USAGE; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; import java.util.Set; -import java.util.stream.Stream; +import seedu.address.commons.util.StringUtil; +import seedu.address.logic.ModuleInfoSearcher; import seedu.address.logic.commands.AddCommand; +import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; +import seedu.address.model.module.ModularCredits; +import seedu.address.model.module.Module; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTitle; import seedu.address.model.tag.Tag; +import seedu.address.nusmods.ModuleInfo; /** * Parses input arguments and creates a new AddCommand object */ public class AddCommandParser implements Parser { + private final ModuleInfoSearcher moduleInfoSearcher; + + /** + * Constructs an AddCommandParser. + */ + public AddCommandParser() { + moduleInfoSearcher = new ModuleInfoSearcher(); + } + + /** + * Constructs an AddCommandParser with a custom ModuleInfoSearcher object. + * This is mainly used for stubbing. + * + * @param moduleInfoSearcher - the custom ModuleInfoSearcher + */ + public AddCommandParser(ModuleInfoSearcher moduleInfoSearcher) { + this.moduleInfoSearcher = moduleInfoSearcher; + } /** * Parses the given {@code String} of arguments in the context of the AddCommand * and returns an AddCommand object for execution. - * @throws ParseException if the user input does not conform the expected format + * + * @throws ParseException if the user input does not conform the expected format or if the module does + * not exist */ public AddCommand parse(String args) throws ParseException { ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); + ArgumentTokenizer.tokenize(args, PREFIX_TAG); - if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL) - || !argMultimap.getPreamble().isEmpty()) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE)); + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty() || argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MESSAGE_ADD_USAGE)); } + ModuleCode moduleCode = ParserUtil.parseModuleCode(argMultimap.getPreamble()); + String moduleCodeText = StringUtil.ignoreCase(moduleCode.toString()); + ModuleInfo moduleInfo; - Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); - Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); - Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); - Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()); + try { + moduleInfo = moduleInfoSearcher.searchModule(moduleCodeText); + } catch (CommandException e) { + throw new ParseException(e.getMessage()); + } + + ModuleTitle moduleTitle = ParserUtil.parseModuleTitle(moduleInfo.getTitle()); + ModularCredits modularCredits = ParserUtil.parseModularCredits(moduleInfo.getModuleCredit()); Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); - Person person = new Person(name, phone, email, address, tagList); + Module module = new Module(moduleCode, moduleTitle, modularCredits, tagList); - return new AddCommand(person); + return new AddCommand(module); } - - /** - * Returns true if none of the prefixes contains empty {@code Optional} values in the given - * {@code ArgumentMultimap}. - */ - private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { - return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); - } - } diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java deleted file mode 100644 index 1e466792b46..00000000000 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ /dev/null @@ -1,76 +0,0 @@ -package seedu.address.logic.parser; - -import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import seedu.address.logic.commands.AddCommand; -import seedu.address.logic.commands.ClearCommand; -import seedu.address.logic.commands.Command; -import seedu.address.logic.commands.DeleteCommand; -import seedu.address.logic.commands.EditCommand; -import seedu.address.logic.commands.ExitCommand; -import seedu.address.logic.commands.FindCommand; -import seedu.address.logic.commands.HelpCommand; -import seedu.address.logic.commands.ListCommand; -import seedu.address.logic.parser.exceptions.ParseException; - -/** - * Parses user input. - */ -public class AddressBookParser { - - /** - * Used for initial separation of command word and args. - */ - private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); - - /** - * Parses user input into command for execution. - * - * @param userInput full user input string - * @return the command based on the user input - * @throws ParseException if the user input does not conform the expected format - */ - public Command parseCommand(String userInput) throws ParseException { - final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); - if (!matcher.matches()) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE)); - } - - final String commandWord = matcher.group("commandWord"); - final String arguments = matcher.group("arguments"); - switch (commandWord) { - - case AddCommand.COMMAND_WORD: - return new AddCommandParser().parse(arguments); - - case EditCommand.COMMAND_WORD: - return new EditCommandParser().parse(arguments); - - case DeleteCommand.COMMAND_WORD: - return new DeleteCommandParser().parse(arguments); - - case ClearCommand.COMMAND_WORD: - return new ClearCommand(); - - case FindCommand.COMMAND_WORD: - return new FindCommandParser().parse(arguments); - - case ListCommand.COMMAND_WORD: - return new ListCommand(); - - case ExitCommand.COMMAND_WORD: - return new ExitCommand(); - - case HelpCommand.COMMAND_WORD: - return new HelpCommand(); - - default: - throw new ParseException(MESSAGE_UNKNOWN_COMMAND); - } - } - -} diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java index 954c8e18f8e..0ef7faf7074 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java +++ b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java @@ -22,7 +22,7 @@ public class ArgumentMultimap { * Associates the specified argument value with {@code prefix} key in this map. * If the map previously contained a mapping for the key, the new value is appended to the list of existing values. * - * @param prefix Prefix key with which the specified argument value is to be associated + * @param prefix Prefix key with which the specified argument value is to be associated * @param argValue Argument value to be associated with the specified prefix key */ public void put(Prefix prefix, String argValue) { diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java index 5c9aebfa488..e1c05d22962 100644 --- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java +++ b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java @@ -144,5 +144,4 @@ Prefix getPrefix() { return prefix; } } - } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 75b1a9bf119..13f498963d0 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -6,10 +6,6 @@ public class CliSyntax { /* Prefix definitions */ - public static final Prefix PREFIX_NAME = new Prefix("n/"); - public static final Prefix PREFIX_PHONE = new Prefix("p/"); - public static final Prefix PREFIX_EMAIL = new Prefix("e/"); - public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); + public static final Prefix PREFIX_CODE = new Prefix("c/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); - } diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java index 522b93081cc..9368aeddd35 100644 --- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java @@ -1,10 +1,12 @@ package seedu.address.logic.parser; +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_DELETE_USAGE; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.DeleteCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.module.ModuleCode; /** * Parses input arguments and creates a new DeleteCommand object @@ -17,13 +19,12 @@ public class DeleteCommandParser implements Parser { * @throws ParseException if the user input does not conform the expected format */ public DeleteCommand parse(String args) throws ParseException { - try { - Index index = ParserUtil.parseIndex(args); - return new DeleteCommand(index); - } catch (ParseException pe) { - throw new ParseException( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe); + requireNonNull(args); + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, MESSAGE_DELETE_USAGE)); } + ModuleCode code = ParserUtil.parseModuleCode(args); + return new DeleteCommand(code); } - } diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java index 845644b7dea..fe1d09dc744 100644 --- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java @@ -1,11 +1,10 @@ package seedu.address.logic.parser; import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_EDIT_USAGE; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; -import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; -import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; -import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; +import static seedu.address.commons.core.Messages.MESSAGE_NOT_EDITED; +import static seedu.address.logic.parser.CliSyntax.PREFIX_CODE; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; import java.util.Collection; @@ -13,55 +12,78 @@ import java.util.Optional; import java.util.Set; -import seedu.address.commons.core.index.Index; +import seedu.address.logic.ModuleInfoSearcher; import seedu.address.logic.commands.EditCommand; -import seedu.address.logic.commands.EditCommand.EditPersonDescriptor; +import seedu.address.logic.commands.EditCommand.EditModuleDescriptor; +import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.module.ModuleCode; import seedu.address.model.tag.Tag; +import seedu.address.nusmods.ModuleInfo; /** * Parses input arguments and creates a new EditCommand object */ public class EditCommandParser implements Parser { + private final ModuleInfoSearcher moduleInfoSearcher; + + /** + * Constructs an EditCommandParser. + */ + public EditCommandParser() { + moduleInfoSearcher = new ModuleInfoSearcher(); + } + + /** + * Constructs an EditCommandParser with a custom ModuleInfoSearcher object. + * This is mainly used for stubbing. + * + * @param moduleInfoSearcher - the custom ModuleInfoSearcher + */ + public EditCommandParser(ModuleInfoSearcher moduleInfoSearcher) { + this.moduleInfoSearcher = moduleInfoSearcher; + } /** * Parses the given {@code String} of arguments in the context of the EditCommand * and returns an EditCommand object for execution. + * * @throws ParseException if the user input does not conform the expected format */ public EditCommand parse(String args) throws ParseException { requireNonNull(args); ArgumentMultimap argMultimap = - ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG); - - Index index; + ArgumentTokenizer.tokenize(args, PREFIX_CODE, PREFIX_TAG); - try { - index = ParserUtil.parseIndex(argMultimap.getPreamble()); - } catch (ParseException pe) { - throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty() || argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MESSAGE_EDIT_USAGE)); } - EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor(); - if (argMultimap.getValue(PREFIX_NAME).isPresent()) { - editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get())); - } - if (argMultimap.getValue(PREFIX_PHONE).isPresent()) { - editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get())); - } - if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { - editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); - } - if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { - editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); + ModuleCode code = ParserUtil.parseModuleCode(argMultimap.getPreamble()); + EditModuleDescriptor editModuleDescriptor = new EditModuleDescriptor(); + ModuleInfo moduleInfo; + + if (argMultimap.getValue(PREFIX_CODE).isPresent()) { + ModuleCode newCode = ParserUtil.parseModuleCode(argMultimap.getValue(PREFIX_CODE).get()); + try { + moduleInfo = moduleInfoSearcher.searchModule(newCode.toString()); + editModuleDescriptor.setModuleCode(newCode); + editModuleDescriptor.setModuleTitle(ParserUtil.parseModuleTitle(moduleInfo.getTitle())); + editModuleDescriptor.setModularCredits( + ParserUtil.parseModularCredits(moduleInfo.getModuleCredit())); + } catch (CommandException e) { + throw new ParseException(e.getMessage()); + } } - parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); + parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editModuleDescriptor::setTags); - if (!editPersonDescriptor.isAnyFieldEdited()) { - throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); + if (!editModuleDescriptor.isAnyFieldEdited()) { + throw new ParseException(MESSAGE_NOT_EDITED); } - return new EditCommand(index, editPersonDescriptor); + return new EditCommand(code, editModuleDescriptor); } /** @@ -78,5 +100,4 @@ private Optional> parseTagsForEdit(Collection tags) throws Pars Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags; return Optional.of(ParserUtil.parseTags(tagSet)); } - } diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java index 4fb71f23103..d707c7824c4 100644 --- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java @@ -1,12 +1,14 @@ package seedu.address.logic.parser; +import static seedu.address.commons.core.Messages.MESSAGE_FIND_USAGE; import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; import java.util.Arrays; +import java.util.List; import seedu.address.logic.commands.FindCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.NameContainsKeywordsPredicate; +import seedu.address.model.module.CompoundFindPredicate; /** * Parses input arguments and creates a new FindCommand object @@ -16,18 +18,18 @@ public class FindCommandParser implements Parser { /** * Parses the given {@code String} of arguments in the context of the FindCommand * and returns a FindCommand object for execution. + * * @throws ParseException if the user input does not conform the expected format */ public FindCommand parse(String args) throws ParseException { String trimmedArgs = args.trim(); if (trimmedArgs.isEmpty()) { throw new ParseException( - String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE)); + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MESSAGE_FIND_USAGE)); } - String[] nameKeywords = trimmedArgs.split("\\s+"); + List keywords = Arrays.asList(trimmedArgs.split("\\s+")); - return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords))); + return new FindCommand(new CompoundFindPredicate(keywords)); } - } diff --git a/src/main/java/seedu/address/logic/parser/ForceDeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/ForceDeleteCommandParser.java new file mode 100644 index 00000000000..3fb24c58a8e --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/ForceDeleteCommandParser.java @@ -0,0 +1,32 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_FORCE_DELETE_USAGE; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.logic.commands.ForceDeleteCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.module.ModuleCode; + +/** + * Parses input arguments and creates a new ForceDeleteCommand object + */ +public class ForceDeleteCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the ForceDeleteCommand + * and returns a ForceDeleteCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public ForceDeleteCommand parse(String args) throws ParseException { + requireNonNull(args); + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, + MESSAGE_FORCE_DELETE_USAGE)); + } + ModuleCode code = ParserUtil.parseModuleCode(args); + return new ForceDeleteCommand(code); + } +} diff --git a/src/main/java/seedu/address/logic/parser/GradPadParser.java b/src/main/java/seedu/address/logic/parser/GradPadParser.java new file mode 100644 index 00000000000..c07e8ef93a0 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/GradPadParser.java @@ -0,0 +1,126 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.ADD_COMMAND_WORD; +import static seedu.address.commons.core.Messages.CHECKMC_COMMAND_WORD; +import static seedu.address.commons.core.Messages.CLEAR_COMMAND_WORD; +import static seedu.address.commons.core.Messages.DELETE_COMMAND_WORD; +import static seedu.address.commons.core.Messages.EDIT_COMMAND_WORD; +import static seedu.address.commons.core.Messages.EXIT_COMMAND_WORD; +import static seedu.address.commons.core.Messages.FIND_COMMAND_WORD; +import static seedu.address.commons.core.Messages.FORCE_CLEAR_COMMAND_WORD; +import static seedu.address.commons.core.Messages.FORCE_DELETE_COMMAND_WORD; +import static seedu.address.commons.core.Messages.GEM_COMMAND_WORD; +import static seedu.address.commons.core.Messages.HELP_COMMAND_WORD; +import static seedu.address.commons.core.Messages.LIST_COMMAND_WORD; +import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND; +import static seedu.address.commons.core.Messages.REQUIRED_COMMAND_WORD; +import static seedu.address.commons.core.Messages.SCIENCE_COMMAND_WORD; +import static seedu.address.commons.core.Messages.SEARCH_COMMAND_WORD; +import static seedu.address.commons.core.Messages.TAGS_COMMAND_WORD; +import static seedu.address.commons.core.Messages.YES_COMMAND_WORD; +import static seedu.address.commons.core.Messages.YE_COMMAND_WORD; +import static seedu.address.commons.core.Messages.Y_COMMAND_WORD; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import seedu.address.commons.core.Messages; +import seedu.address.logic.commands.CheckMcCommand; +import seedu.address.logic.commands.ClearCommand; +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.ExitCommand; +import seedu.address.logic.commands.ForceClearCommand; +import seedu.address.logic.commands.GemCommand; +import seedu.address.logic.commands.HelpCommand; +import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.RequiredCommand; +import seedu.address.logic.commands.ScienceCommand; +import seedu.address.logic.commands.TagsCommand; +import seedu.address.logic.commands.YesCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses user input. + */ +public class GradPadParser { + + /** + * Used for initial separation of command word and args. + */ + private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)"); + + /** + * Parses user input into command for execution. + * + * @param userInput full user input string + * @return the command based on the user input + * @throws ParseException if the user input does not conform the expected format + */ + public Command parseCommand(String userInput) throws ParseException { + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim()); + if (!matcher.matches()) { + throw new ParseException(Messages.MESSAGE_EMPTY_FIELD); + } + + final String commandWord = matcher.group("commandWord").toLowerCase(); + final String arguments = matcher.group("arguments"); + switch (commandWord) { + + case ADD_COMMAND_WORD: + return new AddCommandParser().parse(arguments); + + case EDIT_COMMAND_WORD: + return new EditCommandParser().parse(arguments); + + case DELETE_COMMAND_WORD: + return new DeleteCommandParser().parse(arguments); + + case FORCE_DELETE_COMMAND_WORD: + return new ForceDeleteCommandParser().parse(arguments); + + case CLEAR_COMMAND_WORD: + return new ClearCommand(); + + case FORCE_CLEAR_COMMAND_WORD: + return new ForceClearCommand(); + + case FIND_COMMAND_WORD: + return new FindCommandParser().parse(arguments); + + case LIST_COMMAND_WORD: + return new ListCommand(); + + case EXIT_COMMAND_WORD: + return new ExitCommand(); + + case HELP_COMMAND_WORD: + return new HelpCommand(); + + case CHECKMC_COMMAND_WORD: + return new CheckMcCommand(); + + case SEARCH_COMMAND_WORD: + return new SearchCommandParser().parse(arguments); + + case REQUIRED_COMMAND_WORD: + return new RequiredCommand(); + + case SCIENCE_COMMAND_WORD: + return new ScienceCommand(); + + case YES_COMMAND_WORD: + case YE_COMMAND_WORD: + case Y_COMMAND_WORD: + return new YesCommand(); + + case TAGS_COMMAND_WORD: + return new TagsCommand(); + + case GEM_COMMAND_WORD: + return new GemCommand(); + + default: + throw new ParseException(MESSAGE_UNKNOWN_COMMAND); + } + } +} diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index b117acb9c55..e42cde3099e 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -1,18 +1,17 @@ package seedu.address.logic.parser; import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_MODULE_CODE; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_TAG; import java.util.Collection; import java.util.HashSet; import java.util.Set; -import seedu.address.commons.core.index.Index; -import seedu.address.commons.util.StringUtil; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Phone; +import seedu.address.model.module.ModularCredits; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTitle; import seedu.address.model.tag.Tag; /** @@ -20,79 +19,43 @@ */ public class ParserUtil { - public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer."; - - /** - * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be - * trimmed. - * @throws ParseException if the specified index is invalid (not non-zero unsigned integer). - */ - public static Index parseIndex(String oneBasedIndex) throws ParseException { - String trimmedIndex = oneBasedIndex.trim(); - if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) { - throw new ParseException(MESSAGE_INVALID_INDEX); - } - return Index.fromOneBased(Integer.parseInt(trimmedIndex)); - } - /** - * Parses a {@code String name} into a {@code Name}. + * Parses a {@code String ModuleTitle} into a {@code ModuleTitle}. * Leading and trailing whitespaces will be trimmed. * - * @throws ParseException if the given {@code name} is invalid. + * @throws ParseException if the given {@code moduleTitle} is invalid. */ - public static Name parseName(String name) throws ParseException { - requireNonNull(name); - String trimmedName = name.trim(); - if (!Name.isValidName(trimmedName)) { - throw new ParseException(Name.MESSAGE_CONSTRAINTS); - } - return new Name(trimmedName); + public static ModuleTitle parseModuleTitle(String moduleTitle) throws ParseException { + requireNonNull(moduleTitle); + String trimmedModuleTitle = moduleTitle.trim(); + return new ModuleTitle(trimmedModuleTitle); } /** - * Parses a {@code String phone} into a {@code Phone}. + * Parses a {@code String code} into a {@code ModuleCode}. * Leading and trailing whitespaces will be trimmed. * - * @throws ParseException if the given {@code phone} is invalid. + * @throws ParseException if the given {@code code} is invalid. */ - public static Phone parsePhone(String phone) throws ParseException { - requireNonNull(phone); - String trimmedPhone = phone.trim(); - if (!Phone.isValidPhone(trimmedPhone)) { - throw new ParseException(Phone.MESSAGE_CONSTRAINTS); + public static ModuleCode parseModuleCode(String code) throws ParseException { + requireNonNull(code); + String modifiedCode = code.trim().toUpperCase(); + if (!ModuleCode.isValidModuleCode(modifiedCode)) { + throw new ParseException(String.format(MESSAGE_INVALID_MODULE_CODE, modifiedCode)); } - return new Phone(trimmedPhone); + return new ModuleCode(modifiedCode); } /** - * Parses a {@code String address} into an {@code Address}. + * Parses a {@code String credits} into a {@code ModularCredits}. * Leading and trailing whitespaces will be trimmed. * - * @throws ParseException if the given {@code address} is invalid. + * @throws ParseException if the given {@code credits} is invalid. */ - public static Address parseAddress(String address) throws ParseException { - requireNonNull(address); - String trimmedAddress = address.trim(); - if (!Address.isValidAddress(trimmedAddress)) { - throw new ParseException(Address.MESSAGE_CONSTRAINTS); - } - return new Address(trimmedAddress); - } - - /** - * Parses a {@code String email} into an {@code Email}. - * Leading and trailing whitespaces will be trimmed. - * - * @throws ParseException if the given {@code email} is invalid. - */ - public static Email parseEmail(String email) throws ParseException { - requireNonNull(email); - String trimmedEmail = email.trim(); - if (!Email.isValidEmail(trimmedEmail)) { - throw new ParseException(Email.MESSAGE_CONSTRAINTS); - } - return new Email(trimmedEmail); + public static ModularCredits parseModularCredits(String credits) throws ParseException { + requireNonNull(credits); + String trimmedCredits = credits.trim(); + return new ModularCredits(trimmedCredits); } /** @@ -105,7 +68,7 @@ public static Tag parseTag(String tag) throws ParseException { requireNonNull(tag); String trimmedTag = tag.trim(); if (!Tag.isValidTagName(trimmedTag)) { - throw new ParseException(Tag.MESSAGE_CONSTRAINTS); + throw new ParseException(String.format(MESSAGE_INVALID_TAG, trimmedTag)); } return new Tag(trimmedTag); } @@ -116,8 +79,12 @@ public static Tag parseTag(String tag) throws ParseException { public static Set parseTags(Collection tags) throws ParseException { requireNonNull(tags); final Set tagSet = new HashSet<>(); + final Set tagNameSet = new HashSet<>(); for (String tagName : tags) { - tagSet.add(parseTag(tagName)); + if (!tagNameSet.contains(tagName.toLowerCase())) { + tagSet.add(parseTag(tagName)); + tagNameSet.add(tagName.toLowerCase()); + } } return tagSet; } diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/address/logic/parser/Prefix.java index c859d5fa5db..883f09e3330 100644 --- a/src/main/java/seedu/address/logic/parser/Prefix.java +++ b/src/main/java/seedu/address/logic/parser/Prefix.java @@ -1,7 +1,7 @@ package seedu.address.logic.parser; /** - * A prefix that marks the beginning of an argument in an arguments string. + * Represents a prefix that marks the beginning of an argument in an arguments string. * E.g. 't/' in 'add James t/ friend'. */ public class Prefix { diff --git a/src/main/java/seedu/address/logic/parser/SearchCommandParser.java b/src/main/java/seedu/address/logic/parser/SearchCommandParser.java new file mode 100644 index 00000000000..2ca611c5121 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/SearchCommandParser.java @@ -0,0 +1,30 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.commons.core.Messages.MESSAGE_SEARCH_USAGE; + +import seedu.address.logic.commands.SearchCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.module.ModuleCode; + +/** + * Parses input arguments and creates a new SearchCommand object + */ +public class SearchCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the SearchCommand + * and returns a SearchCommand object for execution. + * + * @throws ParseException if the user input does not conform the expected format + */ + public SearchCommand parse(String args) throws ParseException { + String trimmedArgs = args.trim(); + if (trimmedArgs.isEmpty()) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, MESSAGE_SEARCH_USAGE)); + } + ModuleCode moduleCode = ParserUtil.parseModuleCode(trimmedArgs); + return new SearchCommand(moduleCode); + } +} diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java index 158a1a54c1c..656a828bc11 100644 --- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java +++ b/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java @@ -10,8 +10,4 @@ public class ParseException extends IllegalValueException { public ParseException(String message) { super(message); } - - public ParseException(String message, Throwable cause) { - super(message, cause); - } } diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java deleted file mode 100644 index 1a943a0781a..00000000000 --- a/src/main/java/seedu/address/model/AddressBook.java +++ /dev/null @@ -1,120 +0,0 @@ -package seedu.address.model; - -import static java.util.Objects.requireNonNull; - -import java.util.List; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; -import seedu.address.model.person.UniquePersonList; - -/** - * Wraps all data at the address-book level - * Duplicates are not allowed (by .isSamePerson comparison) - */ -public class AddressBook implements ReadOnlyAddressBook { - - private final UniquePersonList persons; - - /* - * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication - * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html - * - * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication - * among constructors. - */ - { - persons = new UniquePersonList(); - } - - public AddressBook() {} - - /** - * Creates an AddressBook using the Persons in the {@code toBeCopied} - */ - public AddressBook(ReadOnlyAddressBook toBeCopied) { - this(); - resetData(toBeCopied); - } - - //// list overwrite operations - - /** - * Replaces the contents of the person list with {@code persons}. - * {@code persons} must not contain duplicate persons. - */ - public void setPersons(List persons) { - this.persons.setPersons(persons); - } - - /** - * Resets the existing data of this {@code AddressBook} with {@code newData}. - */ - public void resetData(ReadOnlyAddressBook newData) { - requireNonNull(newData); - - setPersons(newData.getPersonList()); - } - - //// person-level operations - - /** - * Returns true if a person with the same identity as {@code person} exists in the address book. - */ - public boolean hasPerson(Person person) { - requireNonNull(person); - return persons.contains(person); - } - - /** - * Adds a person to the address book. - * The person must not already exist in the address book. - */ - public void addPerson(Person p) { - persons.add(p); - } - - /** - * Replaces the given person {@code target} in the list with {@code editedPerson}. - * {@code target} must exist in the address book. - * The person identity of {@code editedPerson} must not be the same as another existing person in the address book. - */ - public void setPerson(Person target, Person editedPerson) { - requireNonNull(editedPerson); - - persons.setPerson(target, editedPerson); - } - - /** - * Removes {@code key} from this {@code AddressBook}. - * {@code key} must exist in the address book. - */ - public void removePerson(Person key) { - persons.remove(key); - } - - //// util methods - - @Override - public String toString() { - return persons.asUnmodifiableObservableList().size() + " persons"; - // TODO: refine later - } - - @Override - public ObservableList getPersonList() { - return persons.asUnmodifiableObservableList(); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof AddressBook // instanceof handles nulls - && persons.equals(((AddressBook) other).persons)); - } - - @Override - public int hashCode() { - return persons.hashCode(); - } -} diff --git a/src/main/java/seedu/address/model/GradPad.java b/src/main/java/seedu/address/model/GradPad.java new file mode 100644 index 00000000000..cf31007c1e1 --- /dev/null +++ b/src/main/java/seedu/address/model/GradPad.java @@ -0,0 +1,161 @@ +package seedu.address.model; + +import static java.util.Objects.requireNonNull; + +import java.util.List; +import java.util.Set; + +import javafx.collections.ObservableList; +import seedu.address.model.module.Module; +import seedu.address.model.module.UniqueModuleList; +import seedu.address.model.tag.Tag; +import seedu.address.model.tag.UniqueTagMap; + +/** + * Wraps all data at the GradPad level + * Duplicates are not allowed (by .isSameModule comparison) + */ +public class GradPad implements ReadOnlyGradPad { + + private final UniqueModuleList modules; + private final UniqueTagMap tags; + + /* + * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication + * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html + * + * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication + * among constructors. + */ + { + modules = new UniqueModuleList(); + tags = new UniqueTagMap(); + } + + public GradPad() {} + + /** + * Creates a GradPad using the Modules in the {@code toBeCopied} + */ + public GradPad(ReadOnlyGradPad toBeCopied) { + this(); + resetData(toBeCopied); + } + + //// list overwrite operations + + /** + * Replaces the contents of the module list with {@code modules}. + * {@code modules} must not contain duplicate modules. + */ + public void setModules(List modules) { + assert modules != null; + this.modules.setModules(modules); + } + + /** + * Replaces the current tags with {@code tags}. + */ + public void setTags(UniqueTagMap tags) { + assert tags != null; + this.tags.setTags(tags); + } + + /** + * Resets the existing data of this {@code GradPad} with {@code newData}. + */ + public void resetData(ReadOnlyGradPad newData) { + requireNonNull(newData); + + setModules(newData.getModuleList()); + setTags(newData.getTags()); + } + + //// list checking operations + + public boolean isEmpty() { + return modules.isEmpty(); + } + + //// module-level operations + + /** + * Returns true if a module with the same identity as {@code module} exists in the GradPad. + */ + public boolean hasModule(Module module) { + requireNonNull(module); + return modules.contains(module); + } + + /** + * Adds a module to the GradPad. + * The module must not already exist in the GradPad. + */ + public void addModule(Module m) { + assert m != null; + + // Reuse existing tags if possible + Module toAdd = getModuleWithReplacedTags(m); + modules.add(toAdd); + } + + /** + * Replaces the given module {@code target} in the list with {@code editedModule}. + * {@code target} must exist in the GradPad. + * The module identity of {@code editedModule} must not be the same as another existing module in the GradPad. + */ + public void setModule(Module target, Module editedModule) { + requireNonNull(editedModule); + + // "untag" all tags in the module we're going to edit + tags.remove(target.getTags()); + // Get new tags and reuse existing tags if possible + Module editedModuleToAdd = getModuleWithReplacedTags(editedModule); + modules.setModule(target, editedModuleToAdd); + } + + /** + * Removes {@code key} from this {@code GradPad}. + * {@code key} must exist in the GradPad. + */ + public void removeModule(Module key) { + assert key != null; + tags.remove(key.getTags()); + modules.remove(key); + } + + //// util methods + private Module getModuleWithReplacedTags(Module m) { + Set replacedTags = tags.checkAndReplaceTags(m.getTags()); + return new Module(m.getModuleCode(), m.getModuleTitle(), + m.getModularCredits(), replacedTags); + } + + @Override + public String toString() { + return modules.asUnmodifiableObservableList().size() + " modules"; + // TODO: refine later + } + + @Override + public ObservableList getModuleList() { + return modules.asUnmodifiableObservableList(); + } + + @Override + public UniqueTagMap getTags() { + return tags; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof GradPad // instanceof handles nulls + && modules.equals(((GradPad) other).modules)); + } + + @Override + public int hashCode() { + return modules.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index d54df471c1f..d88c3d736b3 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -5,14 +5,14 @@ import javafx.collections.ObservableList; import seedu.address.commons.core.GuiSettings; -import seedu.address.model.person.Person; +import seedu.address.model.module.Module; /** * The API of the Model component. */ public interface Model { /** {@code Predicate} that always evaluate to true */ - Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true; + Predicate PREDICATE_SHOW_ALL_MODULES = unused -> true; /** * Replaces user prefs data with the data in {@code userPrefs}. @@ -35,53 +35,58 @@ public interface Model { void setGuiSettings(GuiSettings guiSettings); /** - * Returns the user prefs' address book file path. + * Returns the user prefs' GradPad file path. */ - Path getAddressBookFilePath(); + Path getGradPadFilePath(); /** - * Sets the user prefs' address book file path. + * Sets the user prefs' GradPad file path. */ - void setAddressBookFilePath(Path addressBookFilePath); + void setGradPadFilePath(Path gradPadFilePath); /** - * Replaces address book data with the data in {@code addressBook}. + * Replaces GradPad data with the data in {@code gradPad}. */ - void setAddressBook(ReadOnlyAddressBook addressBook); + void setGradPad(ReadOnlyGradPad gradPad); - /** Returns the AddressBook */ - ReadOnlyAddressBook getAddressBook(); + /** Returns the GradPad */ + ReadOnlyGradPad getGradPad(); /** - * Returns true if a person with the same identity as {@code person} exists in the address book. + * Returns true if a module with the same identity as {@code module} exists in the GradPad. */ - boolean hasPerson(Person person); + boolean hasModule(Module module); /** - * Deletes the given person. - * The person must exist in the address book. + * Returns true if the GradPad is empty. */ - void deletePerson(Person target); + boolean isEmpty(); /** - * Adds the given person. - * {@code person} must not already exist in the address book. + * Deletes the given module. + * The module must exist in the GradPad. */ - void addPerson(Person person); + void deleteModule(Module target); /** - * Replaces the given person {@code target} with {@code editedPerson}. - * {@code target} must exist in the address book. - * The person identity of {@code editedPerson} must not be the same as another existing person in the address book. + * Adds the given module. + * {@code module} must not already exist in the GradPad. */ - void setPerson(Person target, Person editedPerson); + void addModule(Module module); - /** Returns an unmodifiable view of the filtered person list */ - ObservableList getFilteredPersonList(); + /** + * Replaces the given module {@code target} with {@code editedModule}. + * {@code target} must exist in the GradPad. + * The module identity of {@code editedModule} must not be the same as another existing module in the GradPad. + */ + void setModule(Module target, Module editedModule); + + /** Returns an unmodifiable view of the filtered module list */ + ObservableList getFilteredModuleList(); /** - * Updates the filter of the filtered person list to filter by the given {@code predicate}. + * Updates the filter of the filtered module list to filter by the given {@code predicate}. * @throws NullPointerException if {@code predicate} is null. */ - void updateFilteredPersonList(Predicate predicate); + void updateFilteredModuleList(Predicate predicate); } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 0650c954f5c..ef3d0053cc9 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -11,34 +11,35 @@ import javafx.collections.transformation.FilteredList; import seedu.address.commons.core.GuiSettings; import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; +import seedu.address.model.module.Module; /** - * Represents the in-memory model of the address book data. + * Represents the in-memory model of the GradPad data. */ public class ModelManager implements Model { private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - private final AddressBook addressBook; + private final GradPad gradPad; private final UserPrefs userPrefs; - private final FilteredList filteredPersons; + private final FilteredList filteredModules; + /** - * Initializes a ModelManager with the given addressBook and userPrefs. + * Initializes a ModelManager with the given GradPad and userPrefs. */ - public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) { + public ModelManager(ReadOnlyGradPad gradPad, ReadOnlyUserPrefs userPrefs) { super(); - requireAllNonNull(addressBook, userPrefs); + requireAllNonNull(gradPad, userPrefs); - logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs); + logger.fine("Initializing with GradPad: " + gradPad + " and user prefs " + userPrefs); - this.addressBook = new AddressBook(addressBook); + this.gradPad = new GradPad(gradPad); this.userPrefs = new UserPrefs(userPrefs); - filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); + filteredModules = new FilteredList<>(this.gradPad.getModuleList()); } public ModelManager() { - this(new AddressBook(), new UserPrefs()); + this(new GradPad(), new UserPrefs()); } //=========== UserPrefs ================================================================================== @@ -66,67 +67,74 @@ public void setGuiSettings(GuiSettings guiSettings) { } @Override - public Path getAddressBookFilePath() { - return userPrefs.getAddressBookFilePath(); + public Path getGradPadFilePath() { + return userPrefs.getGradPadFilePath(); } @Override - public void setAddressBookFilePath(Path addressBookFilePath) { - requireNonNull(addressBookFilePath); - userPrefs.setAddressBookFilePath(addressBookFilePath); + public void setGradPadFilePath(Path gradPadFilePath) { + requireNonNull(gradPadFilePath); + userPrefs.setGradPadFilePath(gradPadFilePath); } - //=========== AddressBook ================================================================================ + //=========== GradPad ================================================================================ + + @Override + public void setGradPad(ReadOnlyGradPad gradPad) { + this.gradPad.resetData(gradPad); + } @Override - public void setAddressBook(ReadOnlyAddressBook addressBook) { - this.addressBook.resetData(addressBook); + public ReadOnlyGradPad getGradPad() { + return gradPad; } @Override - public ReadOnlyAddressBook getAddressBook() { - return addressBook; + public boolean hasModule(Module module) { + requireNonNull(module); + return gradPad.hasModule(module); } @Override - public boolean hasPerson(Person person) { - requireNonNull(person); - return addressBook.hasPerson(person); + public boolean isEmpty() { + return gradPad.isEmpty(); } @Override - public void deletePerson(Person target) { - addressBook.removePerson(target); + public void deleteModule(Module target) { + assert target != null; + gradPad.removeModule(target); } @Override - public void addPerson(Person person) { - addressBook.addPerson(person); - updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + public void addModule(Module module) { + assert module != null; + gradPad.addModule(module); + updateFilteredModuleList(PREDICATE_SHOW_ALL_MODULES); } @Override - public void setPerson(Person target, Person editedPerson) { - requireAllNonNull(target, editedPerson); + public void setModule(Module target, Module editedModule) { + requireAllNonNull(target, editedModule); - addressBook.setPerson(target, editedPerson); + gradPad.setModule(target, editedModule); } - //=========== Filtered Person List Accessors ============================================================= + //=========== Filtered Module List Accessors ============================================================= /** - * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of - * {@code versionedAddressBook} + * Returns an unmodifiable view of the list of {@code Module} backed by the internal list of + * {@code versionedGradPad} */ @Override - public ObservableList getFilteredPersonList() { - return filteredPersons; + public ObservableList getFilteredModuleList() { + return filteredModules; } @Override - public void updateFilteredPersonList(Predicate predicate) { + public void updateFilteredModuleList(Predicate predicate) { requireNonNull(predicate); - filteredPersons.setPredicate(predicate); + filteredModules.setPredicate(predicate); } @Override @@ -143,9 +151,9 @@ public boolean equals(Object obj) { // state check ModelManager other = (ModelManager) obj; - return addressBook.equals(other.addressBook) + return gradPad.equals(other.gradPad) && userPrefs.equals(other.userPrefs) - && filteredPersons.equals(other.filteredPersons); + && filteredModules.equals(other.filteredModules); } } diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java deleted file mode 100644 index 6ddc2cd9a29..00000000000 --- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java +++ /dev/null @@ -1,17 +0,0 @@ -package seedu.address.model; - -import javafx.collections.ObservableList; -import seedu.address.model.person.Person; - -/** - * Unmodifiable view of an address book - */ -public interface ReadOnlyAddressBook { - - /** - * Returns an unmodifiable view of the persons list. - * This list will not contain any duplicate persons. - */ - ObservableList getPersonList(); - -} diff --git a/src/main/java/seedu/address/model/ReadOnlyGradPad.java b/src/main/java/seedu/address/model/ReadOnlyGradPad.java new file mode 100644 index 00000000000..6c33b6c7758 --- /dev/null +++ b/src/main/java/seedu/address/model/ReadOnlyGradPad.java @@ -0,0 +1,22 @@ +package seedu.address.model; + +import javafx.collections.ObservableList; +import seedu.address.model.module.Module; +import seedu.address.model.tag.UniqueTagMap; + +/** + * Unmodifiable view of a GradPad + */ +public interface ReadOnlyGradPad { + + /** + * Returns an unmodifiable view of the module list. + * This list will not contain any duplicate modules. + */ + ObservableList getModuleList(); + + /** + * Returns the unique tags in the GradPad. + */ + UniqueTagMap getTags(); +} diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java index befd58a4c73..8d95602a5f9 100644 --- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java +++ b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java @@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs { GuiSettings getGuiSettings(); - Path getAddressBookFilePath(); + Path getGradPadFilePath(); } diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java index 25a5fd6eab9..d7c1918b2f1 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/seedu/address/model/UserPrefs.java @@ -14,7 +14,7 @@ public class UserPrefs implements ReadOnlyUserPrefs { private GuiSettings guiSettings = new GuiSettings(); - private Path addressBookFilePath = Paths.get("data" , "addressbook.json"); + private Path gradPadFilePath = Paths.get("data" , "gradpad.json"); /** * Creates a {@code UserPrefs} with default values. @@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) { public void resetData(ReadOnlyUserPrefs newUserPrefs) { requireNonNull(newUserPrefs); setGuiSettings(newUserPrefs.getGuiSettings()); - setAddressBookFilePath(newUserPrefs.getAddressBookFilePath()); + setGradPadFilePath(newUserPrefs.getGradPadFilePath()); } public GuiSettings getGuiSettings() { @@ -47,13 +47,13 @@ public void setGuiSettings(GuiSettings guiSettings) { this.guiSettings = guiSettings; } - public Path getAddressBookFilePath() { - return addressBookFilePath; + public Path getGradPadFilePath() { + return gradPadFilePath; } - public void setAddressBookFilePath(Path addressBookFilePath) { - requireNonNull(addressBookFilePath); - this.addressBookFilePath = addressBookFilePath; + public void setGradPadFilePath(Path gradPadFilePath) { + requireNonNull(gradPadFilePath); + this.gradPadFilePath = gradPadFilePath; } @Override @@ -68,19 +68,19 @@ public boolean equals(Object other) { UserPrefs o = (UserPrefs) other; return guiSettings.equals(o.guiSettings) - && addressBookFilePath.equals(o.addressBookFilePath); + && gradPadFilePath.equals(o.gradPadFilePath); } @Override public int hashCode() { - return Objects.hash(guiSettings, addressBookFilePath); + return Objects.hash(guiSettings, gradPadFilePath); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Gui Settings : " + guiSettings); - sb.append("\nLocal data file location : " + addressBookFilePath); + sb.append("\nLocal data file location : " + gradPadFilePath); return sb.toString(); } diff --git a/src/main/java/seedu/address/model/module/CompoundFindPredicate.java b/src/main/java/seedu/address/model/module/CompoundFindPredicate.java new file mode 100644 index 00000000000..72b0727a131 --- /dev/null +++ b/src/main/java/seedu/address/model/module/CompoundFindPredicate.java @@ -0,0 +1,27 @@ +package seedu.address.model.module; + +import java.util.List; +import java.util.function.Predicate; + +public class CompoundFindPredicate implements Predicate { + private final List keywords; + + public CompoundFindPredicate(List keywords) { + this.keywords = keywords; + } + + @Override + public boolean test(Module module) { + Predicate moduleCodePredicate = new ModuleCodeContainsKeywordsPredicate(keywords); + Predicate tagsPredicate = new ModuleContainsTagsPredicate(keywords); + // chain the predicates + return moduleCodePredicate.or(tagsPredicate).test(module); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof CompoundFindPredicate // instanceof handles nulls + && keywords.equals(((CompoundFindPredicate) other).keywords)); // state check + } +} diff --git a/src/main/java/seedu/address/model/module/ModularCredits.java b/src/main/java/seedu/address/model/module/ModularCredits.java new file mode 100644 index 00000000000..a75ed0d5ef0 --- /dev/null +++ b/src/main/java/seedu/address/model/module/ModularCredits.java @@ -0,0 +1,40 @@ +package seedu.address.model.module; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a Module's no. of modular credits in the GradPad. + * * Guarantees: immutable. + */ +public class ModularCredits { + + public static final String VALIDATION_REGEX = "\\d{1,2}"; + public final String value; + + /** + * Constructs a {@code ModularCredits}. + * + * @param credits A valid value of modular credits. + */ + public ModularCredits(String credits) { + requireNonNull(credits); + value = credits; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ModularCredits // instanceof handles nulls + && value.equals(((ModularCredits) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/module/Module.java b/src/main/java/seedu/address/model/module/Module.java new file mode 100644 index 00000000000..d4f107c6a0c --- /dev/null +++ b/src/main/java/seedu/address/model/module/Module.java @@ -0,0 +1,114 @@ +package seedu.address.model.module; + +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import seedu.address.model.tag.Tag; + +/** + * Represents a Module in the GradPad. + * Guarantees: details are present and not null, field values are validated, immutable. + */ +public class Module { + + // Identity fields + private final ModuleCode code; + private final ModuleTitle title; + private final ModularCredits credits; + + // Data fields + private final Set tags = new HashSet<>(); + + /** + * Every field must be present and not null. + */ + public Module(ModuleCode code, ModuleTitle title, ModularCredits credits, Set tags) { + requireAllNonNull(code, title, credits, tags); + this.code = code; + this.title = title; + this.credits = credits; + this.tags.addAll(tags); + } + + public ModuleCode getModuleCode() { + return code; + } + + public ModuleTitle getModuleTitle() { + return title; + } + + public ModularCredits getModularCredits() { + return credits; + } + + /** + * Returns an immutable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + */ + public Set getTags() { + return Collections.unmodifiableSet(tags); + } + + /** + * Returns true if both modules of the same module code have at least one other field that is the same. + * This defines a weaker notion of equality between two modules. + */ + public boolean isSameModule(Module otherModule) { + if (otherModule == this) { + return true; + } + + return otherModule != null + && otherModule.getModuleCode().equals(getModuleCode()); + } + + /** + * Returns true if both modules have the same fields. + * This defines a stronger notion of equality between two modules. + */ + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof Module)) { + return false; + } + + Module otherModule = (Module) other; + return otherModule.getModularCredits().equals(getModularCredits()) + && otherModule.getModuleCode().equals(getModuleCode()) + && otherModule.getModuleTitle().equals(getModuleTitle()) + && otherModule.getTags().equals(getTags()); + } + + @Override + public int hashCode() { + // use this method for custom fields hashing instead of implementing your own + return Objects.hash(code, title, credits, tags); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("Module Code: ") + .append("\t\t" + getModuleCode()) + .append("\nModule Title: ") + .append("\t\t" + getModuleTitle()) + .append("\nModular Credits: ") + .append("\t" + getModularCredits()) + .append("\nTags: \t\t\t"); + if (tags.isEmpty()) { + builder.append("None"); + } else { + getTags().forEach(builder::append); + } + return builder.toString(); + } +} diff --git a/src/main/java/seedu/address/model/module/ModuleCode.java b/src/main/java/seedu/address/model/module/ModuleCode.java new file mode 100644 index 00000000000..3b96e94dcce --- /dev/null +++ b/src/main/java/seedu/address/model/module/ModuleCode.java @@ -0,0 +1,57 @@ +package seedu.address.model.module; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_CONSTRAINTS_CODE; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a Module's module code in the GradPad. + * Guarantees: immutable; is valid as declared in {@link #isValidModuleCode(String)} + */ +public class ModuleCode { + + /* + A module code must have 2 or more characters as its prefix followed by 1 or more digits as its numerical + code. It can optionally end with 1 or more characters as a suffix. It is also case-insensitive. + */ + public static final String VALIDATION_REGEX = "[\\p{Alpha}]{2,}\\d+[\\p{Alpha}]*"; + + public final String moduleCode; + + /** + * Constructs a {@code ModuleCode}. + * + * @param moduleCode A valid module code. + * + */ + public ModuleCode(String moduleCode) { + requireNonNull(moduleCode); + checkArgument(isValidModuleCode(moduleCode), MESSAGE_CONSTRAINTS_CODE); + this.moduleCode = moduleCode; + } + + /** + * Returns true if a given string is a valid module code. + */ + public static boolean isValidModuleCode(String test) { + return test.matches(VALIDATION_REGEX); + } + + + @Override + public String toString() { + return moduleCode; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ModuleCode // instanceof handles nulls + && moduleCode.equals(((ModuleCode) other).moduleCode)); // state check + } + + @Override + public int hashCode() { + return moduleCode.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/module/ModuleCodeContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/module/ModuleCodeContainsKeywordsPredicate.java new file mode 100644 index 00000000000..bbdbe5aa2a6 --- /dev/null +++ b/src/main/java/seedu/address/model/module/ModuleCodeContainsKeywordsPredicate.java @@ -0,0 +1,39 @@ +package seedu.address.model.module; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; + +/** + * Tests that a {@code Module}'s {@code module code} matches any of the keywords given. + */ +public class ModuleCodeContainsKeywordsPredicate implements Predicate { + private final List keywords; + + /** + * Creates a new ModuleCodeContainsKeywordsPredicate to test whether a module code matches the contains + * the keywords in the specified list. + * + * @param keywords list of keywords. + */ + public ModuleCodeContainsKeywordsPredicate(List keywords) { + assert(keywords != null); + this.keywords = keywords; + } + + @Override + public boolean test(Module module) { + return keywords.stream() + .anyMatch(keyword -> StringUtil.containsCharSequenceIgnoreCase(module.getModuleCode().moduleCode, + keyword)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ModuleCodeContainsKeywordsPredicate // instanceof handles nulls + && keywords.equals(((ModuleCodeContainsKeywordsPredicate) other).keywords)); // state check + } + +} diff --git a/src/main/java/seedu/address/model/module/ModuleContainsTagsPredicate.java b/src/main/java/seedu/address/model/module/ModuleContainsTagsPredicate.java new file mode 100644 index 00000000000..67e980a9597 --- /dev/null +++ b/src/main/java/seedu/address/model/module/ModuleContainsTagsPredicate.java @@ -0,0 +1,30 @@ +package seedu.address.model.module; + +import java.util.List; +import java.util.function.Predicate; + +import seedu.address.commons.util.StringUtil; + +/** + * Tests that a {@code Module} contains a {@code Tag} matching any of the tag names given. + */ +public class ModuleContainsTagsPredicate implements Predicate { + private final List tagNames; + + /** + * Creates a new ModuleContainsTagsPredicate to test whether a module contains any tag that + * matches any of the tag names in the specified list. + * + * @param tagNames list of tag names. + */ + public ModuleContainsTagsPredicate(List tagNames) { + this.tagNames = tagNames; + } + + @Override + public boolean test(Module module) { + return tagNames.stream().anyMatch(name -> + module.getTags().stream().anyMatch(tag -> + StringUtil.containsCharSequenceIgnoreCase(tag.tagName, name))); + } +} diff --git a/src/main/java/seedu/address/model/module/ModuleTitle.java b/src/main/java/seedu/address/model/module/ModuleTitle.java new file mode 100644 index 00000000000..3c96d9dc30d --- /dev/null +++ b/src/main/java/seedu/address/model/module/ModuleTitle.java @@ -0,0 +1,39 @@ +package seedu.address.model.module; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a Module's module title in the GradPad. + * * Guarantees: immutable. + */ +public class ModuleTitle { + + public final String moduleTitle; + + /** + * Constructs a {@code ModuleTitle}. + * + * @param moduleTitle A valid module title. + */ + public ModuleTitle(String moduleTitle) { + requireNonNull(moduleTitle); + this.moduleTitle = moduleTitle; + } + + @Override + public String toString() { + return moduleTitle; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof ModuleTitle // instanceof handles nulls + && moduleTitle.equals(((ModuleTitle) other).moduleTitle)); // state check + } + + @Override + public int hashCode() { + return moduleTitle.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/module/UniqueModuleList.java b/src/main/java/seedu/address/model/module/UniqueModuleList.java new file mode 100644 index 00000000000..197cd2f0c10 --- /dev/null +++ b/src/main/java/seedu/address/model/module/UniqueModuleList.java @@ -0,0 +1,143 @@ +package seedu.address.model.module; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; + +import java.util.Iterator; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import seedu.address.model.module.exceptions.DuplicateModuleException; +import seedu.address.model.module.exceptions.ModuleNotFoundException; + +/** + * A list of modules that enforces uniqueness between its elements and does not allow nulls. + * A module is considered unique by comparing using {@code Module#isSameModule(Module)}. As such, adding and + * updating of modules uses Module#isSameModule(Module) for equality so as to ensure that the module being + * added or updated is unique in terms of identity in the UniqueModuleList. However, the removal of a module + * uses Module#equals(Object) so as to ensure that the Module with exactly the same fields will be removed. + * + * Supports a minimal set of list operations. + * + * @see Module#isSameModule(Module) + */ +public class UniqueModuleList implements Iterable { + + private final ObservableList internalList = FXCollections.observableArrayList(); + private final ObservableList internalUnmodifiableList = + FXCollections.unmodifiableObservableList(internalList); + + /** + * Returns true if the list contains an equivalent module as the given argument. + */ + public boolean contains(Module toCheck) { + requireNonNull(toCheck); + return internalList.stream().anyMatch(toCheck::isSameModule); + } + + /** + * Returns true if the list is empty. + */ + public boolean isEmpty() { + return internalList.isEmpty(); + } + + /** + * Adds a module to the list. + * The module must not already exist in the list. + */ + public void add(Module toAdd) { + requireNonNull(toAdd); + if (contains(toAdd)) { + throw new DuplicateModuleException(); + } + internalList.add(toAdd); + } + + /** + * Replaces the module {@code target} in the list with {@code editedModule}. + * {@code target} must exist in the list. + * The module {@code editedModule} must not be the same as another existing module in the list. + */ + public void setModule(Module target, Module editedModule) { + requireAllNonNull(target, editedModule); + int index = internalList.indexOf(target); + if (index == -1) { + throw new ModuleNotFoundException(); + } + + if (!target.isSameModule(editedModule) && contains(editedModule)) { + throw new DuplicateModuleException(); + } + + internalList.set(index, editedModule); + } + + /** + * Removes the equivalent module from the list. + * The module must exist in the list. + */ + public void remove(Module toRemove) { + requireNonNull(toRemove); + if (!internalList.remove(toRemove)) { + throw new ModuleNotFoundException(); + } + } + + public void setModules(UniqueModuleList replacement) { + requireNonNull(replacement); + internalList.setAll(replacement.internalList); + } + + /** + * Replaces the contents of this list with {@code modules}. + * {@code modules} must not contain duplicate modules. + */ + public void setModules(List modules) { + requireAllNonNull(modules); + if (!modulesAreUnique(modules)) { + throw new DuplicateModuleException(); + } + + internalList.setAll(modules); + } + + /** + * Returns the backing list as an unmodifiable {@code ObservableList}. + */ + public ObservableList asUnmodifiableObservableList() { + return internalUnmodifiableList; + } + + @Override + public Iterator iterator() { + return internalList.iterator(); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof UniqueModuleList// instanceof handles nulls + && internalList.equals(((UniqueModuleList) other).internalList)); + } + + @Override + public int hashCode() { + return internalList.hashCode(); + } + + /** + * Returns true if {@code modules} contains only unique modules. + */ + private boolean modulesAreUnique(List modules) { + for (int i = 0; i < modules.size() - 1; i++) { + for (int j = i + 1; j < modules.size(); j++) { + if (modules.get(i).isSameModule(modules.get(j))) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/seedu/address/model/module/exceptions/DuplicateModuleException.java b/src/main/java/seedu/address/model/module/exceptions/DuplicateModuleException.java new file mode 100644 index 00000000000..418f82ef450 --- /dev/null +++ b/src/main/java/seedu/address/model/module/exceptions/DuplicateModuleException.java @@ -0,0 +1,11 @@ +package seedu.address.model.module.exceptions; + +/** + * Signals that the operation will result in duplicate Modules (Modules are considered duplicates if they have the same + * identity). + */ +public class DuplicateModuleException extends RuntimeException { + public DuplicateModuleException() { + super("Operation would result in duplicate modules"); + } +} diff --git a/src/main/java/seedu/address/model/module/exceptions/ModuleNotFoundException.java b/src/main/java/seedu/address/model/module/exceptions/ModuleNotFoundException.java new file mode 100644 index 00000000000..7b80a6296ea --- /dev/null +++ b/src/main/java/seedu/address/model/module/exceptions/ModuleNotFoundException.java @@ -0,0 +1,6 @@ +package seedu.address.model.module.exceptions; + +/** + * Signals that the operation is unable to find the specified Module. + */ +public class ModuleNotFoundException extends RuntimeException {} diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java deleted file mode 100644 index 60472ca22a0..00000000000 --- a/src/main/java/seedu/address/model/person/Address.java +++ /dev/null @@ -1,57 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's address in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)} - */ -public class Address { - - public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank"; - - /* - * The first character of the address must not be a whitespace, - * otherwise " " (a blank string) becomes a valid input. - */ - public static final String VALIDATION_REGEX = "[^\\s].*"; - - public final String value; - - /** - * Constructs an {@code Address}. - * - * @param address A valid address. - */ - public Address(String address) { - requireNonNull(address); - checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS); - value = address; - } - - /** - * Returns true if a given string is a valid email. - */ - public static boolean isValidAddress(String test) { - return test.matches(VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Address // instanceof handles nulls - && value.equals(((Address) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java deleted file mode 100644 index a5bbe0b6a5f..00000000000 --- a/src/main/java/seedu/address/model/person/Email.java +++ /dev/null @@ -1,67 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's email in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)} - */ -public class Email { - - private static final String SPECIAL_CHARACTERS = "!#$%&'*+/=?`{|}~^.-"; - public static final String MESSAGE_CONSTRAINTS = "Emails should be of the format local-part@domain " - + "and adhere to the following constraints:\n" - + "1. The local-part should only contain alphanumeric characters and these special characters, excluding " - + "the parentheses, (" + SPECIAL_CHARACTERS + ") .\n" - + "2. This is followed by a '@' and then a domain name. " - + "The domain name must:\n" - + " - be at least 2 characters long\n" - + " - start and end with alphanumeric characters\n" - + " - consist of alphanumeric characters, a period or a hyphen for the characters in between, if any."; - // alphanumeric and special characters - private static final String LOCAL_PART_REGEX = "^[\\w" + SPECIAL_CHARACTERS + "]+"; - private static final String DOMAIN_FIRST_CHARACTER_REGEX = "[^\\W_]"; // alphanumeric characters except underscore - private static final String DOMAIN_MIDDLE_REGEX = "[a-zA-Z0-9.-]*"; // alphanumeric, period and hyphen - private static final String DOMAIN_LAST_CHARACTER_REGEX = "[^\\W_]$"; - public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" - + DOMAIN_FIRST_CHARACTER_REGEX + DOMAIN_MIDDLE_REGEX + DOMAIN_LAST_CHARACTER_REGEX; - - public final String value; - - /** - * Constructs an {@code Email}. - * - * @param email A valid email address. - */ - public Email(String email) { - requireNonNull(email); - checkArgument(isValidEmail(email), MESSAGE_CONSTRAINTS); - value = email; - } - - /** - * Returns if a given string is a valid email. - */ - public static boolean isValidEmail(String test) { - return test.matches(VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Email // instanceof handles nulls - && value.equals(((Email) other).value)); // state check - } - - @Override - public int hashCode() { - return value.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java deleted file mode 100644 index 79244d71cf7..00000000000 --- a/src/main/java/seedu/address/model/person/Name.java +++ /dev/null @@ -1,59 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's name in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} - */ -public class Name { - - public static final String MESSAGE_CONSTRAINTS = - "Names should only contain alphanumeric characters and spaces, and it should not be blank"; - - /* - * The first character of the address must not be a whitespace, - * otherwise " " (a blank string) becomes a valid input. - */ - public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; - - public final String fullName; - - /** - * Constructs a {@code Name}. - * - * @param name A valid name. - */ - public Name(String name) { - requireNonNull(name); - checkArgument(isValidName(name), MESSAGE_CONSTRAINTS); - fullName = name; - } - - /** - * Returns true if a given string is a valid name. - */ - public static boolean isValidName(String test) { - return test.matches(VALIDATION_REGEX); - } - - - @Override - public String toString() { - return fullName; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Name // instanceof handles nulls - && fullName.equals(((Name) other).fullName)); // state check - } - - @Override - public int hashCode() { - return fullName.hashCode(); - } - -} diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java deleted file mode 100644 index c9b5868427c..00000000000 --- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java +++ /dev/null @@ -1,31 +0,0 @@ -package seedu.address.model.person; - -import java.util.List; -import java.util.function.Predicate; - -import seedu.address.commons.util.StringUtil; - -/** - * Tests that a {@code Person}'s {@code Name} matches any of the keywords given. - */ -public class NameContainsKeywordsPredicate implements Predicate { - private final List keywords; - - public NameContainsKeywordsPredicate(List keywords) { - this.keywords = keywords; - } - - @Override - public boolean test(Person person) { - return keywords.stream() - .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)); - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls - && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check - } - -} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java deleted file mode 100644 index 557a7a60cd5..00000000000 --- a/src/main/java/seedu/address/model/person/Person.java +++ /dev/null @@ -1,120 +0,0 @@ -package seedu.address.model.person; - -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import seedu.address.model.tag.Tag; - -/** - * Represents a Person in the address book. - * Guarantees: details are present and not null, field values are validated, immutable. - */ -public class Person { - - // Identity fields - private final Name name; - private final Phone phone; - private final Email email; - - // Data fields - private final Address address; - private final Set tags = new HashSet<>(); - - /** - * Every field must be present and not null. - */ - public Person(Name name, Phone phone, Email email, Address address, Set tags) { - requireAllNonNull(name, phone, email, address, tags); - this.name = name; - this.phone = phone; - this.email = email; - this.address = address; - this.tags.addAll(tags); - } - - public Name getName() { - return name; - } - - public Phone getPhone() { - return phone; - } - - public Email getEmail() { - return email; - } - - public Address getAddress() { - return address; - } - - /** - * Returns an immutable tag set, which throws {@code UnsupportedOperationException} - * if modification is attempted. - */ - public Set getTags() { - return Collections.unmodifiableSet(tags); - } - - /** - * Returns true if both persons of the same name have at least one other identity field that is the same. - * This defines a weaker notion of equality between two persons. - */ - public boolean isSamePerson(Person otherPerson) { - if (otherPerson == this) { - return true; - } - - return otherPerson != null - && otherPerson.getName().equals(getName()) - && (otherPerson.getPhone().equals(getPhone()) || otherPerson.getEmail().equals(getEmail())); - } - - /** - * Returns true if both persons have the same identity and data fields. - * This defines a stronger notion of equality between two persons. - */ - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - - if (!(other instanceof Person)) { - return false; - } - - Person otherPerson = (Person) other; - return otherPerson.getName().equals(getName()) - && otherPerson.getPhone().equals(getPhone()) - && otherPerson.getEmail().equals(getEmail()) - && otherPerson.getAddress().equals(getAddress()) - && otherPerson.getTags().equals(getTags()); - } - - @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() { - final StringBuilder builder = new StringBuilder(); - builder.append(getName()) - .append(" Phone: ") - .append(getPhone()) - .append(" Email: ") - .append(getEmail()) - .append(" Address: ") - .append(getAddress()) - .append(" Tags: "); - getTags().forEach(builder::append); - return builder.toString(); - } - -} diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/person/Phone.java deleted file mode 100644 index 872c76b382f..00000000000 --- a/src/main/java/seedu/address/model/person/Phone.java +++ /dev/null @@ -1,53 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.AppUtil.checkArgument; - -/** - * Represents a Person's phone number in the address book. - * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)} - */ -public class Phone { - - - public static final String MESSAGE_CONSTRAINTS = - "Phone numbers should only contain numbers, and it should be at least 3 digits long"; - public static final String VALIDATION_REGEX = "\\d{3,}"; - public final String value; - - /** - * Constructs a {@code Phone}. - * - * @param phone A valid phone number. - */ - public Phone(String phone) { - requireNonNull(phone); - checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS); - value = phone; - } - - /** - * Returns true if a given string is a valid phone number. - */ - public static boolean isValidPhone(String test) { - return test.matches(VALIDATION_REGEX); - } - - @Override - public String toString() { - return value; - } - - @Override - public boolean equals(Object other) { - return other == this // short circuit if same object - || (other instanceof Phone // instanceof handles nulls - && 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 0fee4fe57e6..00000000000 --- a/src/main/java/seedu/address/model/person/UniquePersonList.java +++ /dev/null @@ -1,137 +0,0 @@ -package seedu.address.model.person; - -import static java.util.Objects.requireNonNull; -import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; - -import java.util.Iterator; -import java.util.List; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import seedu.address.model.person.exceptions.DuplicatePersonException; -import seedu.address.model.person.exceptions.PersonNotFoundException; - -/** - * A list of persons that enforces uniqueness between its elements and does not allow nulls. - * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of - * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is - * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so - * as to ensure that the person with exactly the same fields will be removed. - * - * Supports a minimal set of list operations. - * - * @see Person#isSamePerson(Person) - */ -public class UniquePersonList implements Iterable { - - private final ObservableList internalList = FXCollections.observableArrayList(); - private final ObservableList internalUnmodifiableList = - FXCollections.unmodifiableObservableList(internalList); - - /** - * Returns true if the list contains an equivalent person as the given argument. - */ - public boolean contains(Person toCheck) { - requireNonNull(toCheck); - return internalList.stream().anyMatch(toCheck::isSamePerson); - } - - /** - * Adds a person to the list. - * The person must not already exist in the list. - */ - public void add(Person toAdd) { - requireNonNull(toAdd); - if (contains(toAdd)) { - throw new DuplicatePersonException(); - } - internalList.add(toAdd); - } - - /** - * Replaces the person {@code target} in the list with {@code editedPerson}. - * {@code target} must exist in the list. - * The person identity of {@code editedPerson} must not be the same as another existing person in the list. - */ - public void setPerson(Person target, Person editedPerson) { - requireAllNonNull(target, editedPerson); - - int index = internalList.indexOf(target); - if (index == -1) { - throw new PersonNotFoundException(); - } - - if (!target.isSamePerson(editedPerson) && contains(editedPerson)) { - throw new DuplicatePersonException(); - } - - internalList.set(index, editedPerson); - } - - /** - * Removes the equivalent person from the list. - * The person must exist in the list. - */ - public void remove(Person toRemove) { - requireNonNull(toRemove); - if (!internalList.remove(toRemove)) { - throw new PersonNotFoundException(); - } - } - - public void setPersons(UniquePersonList replacement) { - requireNonNull(replacement); - internalList.setAll(replacement.internalList); - } - - /** - * Replaces the contents of this list with {@code persons}. - * {@code persons} must not contain duplicate persons. - */ - public void setPersons(List persons) { - requireAllNonNull(persons); - if (!personsAreUnique(persons)) { - throw new DuplicatePersonException(); - } - - internalList.setAll(persons); - } - - /** - * Returns the backing list as an unmodifiable {@code ObservableList}. - */ - public ObservableList asUnmodifiableObservableList() { - return internalUnmodifiableList; - } - - @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 - && internalList.equals(((UniquePersonList) other).internalList)); - } - - @Override - public int hashCode() { - return internalList.hashCode(); - } - - /** - * Returns true if {@code persons} contains only unique persons. - */ - private boolean personsAreUnique(List persons) { - for (int i = 0; i < persons.size() - 1; i++) { - for (int j = i + 1; j < persons.size(); j++) { - if (persons.get(i).isSamePerson(persons.get(j))) { - return false; - } - } - } - return true; - } -} diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java deleted file mode 100644 index d7290f59442..00000000000 --- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java +++ /dev/null @@ -1,11 +0,0 @@ -package seedu.address.model.person.exceptions; - -/** - * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same - * identity). - */ -public class DuplicatePersonException extends RuntimeException { - public DuplicatePersonException() { - super("Operation would result in duplicate persons"); - } -} diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java deleted file mode 100644 index fa764426ca7..00000000000 --- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java +++ /dev/null @@ -1,6 +0,0 @@ -package seedu.address.model.person.exceptions; - -/** - * Signals that the operation is unable to find the specified person. - */ -public class PersonNotFoundException extends RuntimeException {} diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java index b0ea7e7dad7..1a58531ff99 100644 --- a/src/main/java/seedu/address/model/tag/Tag.java +++ b/src/main/java/seedu/address/model/tag/Tag.java @@ -1,28 +1,31 @@ package seedu.address.model.tag; import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_CONSTRAINTS_TAG; import static seedu.address.commons.util.AppUtil.checkArgument; /** - * Represents a Tag in the address book. + * Represents a Tag in the GradPad. * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)} */ public class Tag { - public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric"; - public static final String VALIDATION_REGEX = "\\p{Alnum}+"; + public static final String VALIDATION_REGEX = "(\\p{Alnum}+\\p{Blank}?)+"; public final String tagName; + private int moduleCount; /** - * Constructs a {@code Tag}. + * Constructs a {@code Tag}. By default, a tag has a module count of 1 since is it constructed by a + * module that contains it. * * @param tagName A valid tag name. */ public Tag(String tagName) { requireNonNull(tagName); - checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS); + checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS_TAG); this.tagName = tagName; + moduleCount = 1; } /** @@ -32,6 +35,42 @@ public static boolean isValidTagName(String test) { return test.matches(VALIDATION_REGEX); } + /** + * Returns the no. of modules that contain this tag. + * + * @return the module count + */ + public int getModuleCount() { + return moduleCount; + } + + /** + * Increments the no. of modules that contain this tag. This is used when: + * 1. A new module with this tag is created + * 2. An existing module is edited to contain this tag + */ + public void incrementModuleCount() { + moduleCount++; + } + + /** + * Decrements the no. of modules that contain this tag. This is used when: + * 1. A module with this tag is deleted + * 2. An existing module is edited and no longer contains this tag + */ + public void decrementModuleCount() { + moduleCount--; + } + + /** + * Checks if this tag is being used by any {@code Module} in GradPad. + * + * @return True if the tag is no longer used by any {@code Module}, false if otherwise. + */ + public boolean isEmpty() { + return moduleCount == 0; + } + @Override public boolean equals(Object other) { return other == this // short circuit if same object diff --git a/src/main/java/seedu/address/model/tag/UniqueTagMap.java b/src/main/java/seedu/address/model/tag/UniqueTagMap.java new file mode 100644 index 00000000000..abc8e1eddb8 --- /dev/null +++ b/src/main/java/seedu/address/model/tag/UniqueTagMap.java @@ -0,0 +1,85 @@ +package seedu.address.model.tag; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Encapsulates data and logic to maintain a set of unique {@code Tag} objects in GradPad. + * With this, duplicate tags are not created in GradPad unnecessarily, thus encouraging reuse of {@code Tag} objects + * across {@code Module} objects. + */ +public class UniqueTagMap { + /** + * A map of tag names to actual {@code Tag} objects + */ + private final Map tagMap = new HashMap<>(); + + /** + * Replaces the current map of {@code Tag} objects with the contents of a new {@code UniqueTagMap}. + * + * @param replacement The replacement {@code UniqueTagMap} to copy from. + */ + public void setTags(UniqueTagMap replacement) { + tagMap.clear(); + tagMap.putAll(replacement.tagMap); + } + + /** + * Given a set of {@code Tags}, decreases the module count of each tag, and if the tag ends up as not being + * used by any {@code Module}, removes it from {@code UniqueTagMap}. This is used to effect "untagging" + * operations, where a module no longer uses these tags, or if a module is deleted. + * + * @param tags The set of tags to "untag". + */ + public void remove(Set tags) { + for (Tag tag : tags) { + tag.decrementModuleCount(); + if (tag.isEmpty()) { + tagMap.remove(tag.tagName); + } + } + } + + /** + * Given a set of {@code Tags}, checks if each tag already exists in {@code UniqueTagMap}. + * If it does, then it replaces that tag with the existing tag so that there is no need to create a new tag. + * Else, it adds that new tag to GradPad. + * + * @param tagsToCheck The set of tags to check through. + * @return The new set of tags which has any duplicate new tags replaced with their existing equivalent. + */ + public Set checkAndReplaceTags(Set tagsToCheck) { + Set replacedTagSet = new HashSet<>(); + + for (Tag tag : tagsToCheck) { + if (tagMap.containsKey(tag.tagName)) { + Tag existingTag = tagMap.get(tag.tagName); + existingTag.incrementModuleCount(); + replacedTagSet.add(existingTag); + } else { + tagMap.put(tag.tagName, tag); + replacedTagSet.add(tag); + } + } + + return replacedTagSet; + } + + /** + * Returns a list of tag names of all tags in {@code UniqueTagMap} + * + * @return a list of tag names + */ + public List getTagNames() { + return new ArrayList<>(tagMap.keySet()); + } + + @Override + public String toString() { + return tagMap.toString(); + } +} diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 1806da4facf..75f704afa1c 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -4,46 +4,39 @@ import java.util.Set; import java.util.stream.Collectors; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; +import seedu.address.model.GradPad; +import seedu.address.model.ReadOnlyGradPad; +import seedu.address.model.module.ModularCredits; +import seedu.address.model.module.Module; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTitle; import seedu.address.model.tag.Tag; /** - * Contains utility methods for populating {@code AddressBook} with sample data. + * Contains utility methods for populating {@code GradPad} with sample data. */ public class SampleDataUtil { - public static Person[] getSamplePersons() { - return new Person[] { - new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), - new Address("Blk 30 Geylang Street 29, #06-40"), - getTagSet("friends")), - new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), - new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), - getTagSet("colleagues", "friends")), - new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), - new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), - getTagSet("neighbours")), - new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), - new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), - getTagSet("family")), - new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), - new Address("Blk 47 Tampines Street 20, #17-35"), - getTagSet("classmates")), - new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), - new Address("Blk 45 Aljunied Street 85, #11-31"), - getTagSet("colleagues")) + public static Module[] getSampleModules() { + return new Module[] { + new Module(new ModuleCode("CS2103T"), new ModuleTitle("Software Engineering"), + new ModularCredits("4"), getTagSet("Foundation")), + new Module(new ModuleCode("CS1010"), new ModuleTitle("Programming Methodology"), + new ModularCredits("4"), getTagSet("Foundation")), + new Module(new ModuleCode("CS2101"), new ModuleTitle("Effective Communication for Computing " + + "Professionals"), new ModularCredits("4"), getTagSet("Foundation")), + new Module(new ModuleCode("CS2105"), new ModuleTitle("Introduction to Computer Networks"), + new ModularCredits("4"), getTagSet("Foundation")), + new Module(new ModuleCode("MA1521"), new ModuleTitle("Calculus for Computing"), + new ModularCredits("4"), getTagSet("MathSci")), + new Module(new ModuleCode("CS2107"), new ModuleTitle("Introduction to Information Security"), + new ModularCredits("4"), getTagSet("BreadthDepth")) }; } - public static ReadOnlyAddressBook getSampleAddressBook() { - AddressBook sampleAb = new AddressBook(); - for (Person samplePerson : getSamplePersons()) { - sampleAb.addPerson(samplePerson); + public static ReadOnlyGradPad getSampleGradPad() { + GradPad sampleAb = new GradPad(); + for (Module sampleModule : getSampleModules()) { + sampleAb.addModule(sampleModule); } return sampleAb; } @@ -56,5 +49,4 @@ public static Set getTagSet(String... strings) { .map(Tag::new) .collect(Collectors.toSet()); } - } diff --git a/src/main/java/seedu/address/nusmods/DataFetcher.java b/src/main/java/seedu/address/nusmods/DataFetcher.java new file mode 100644 index 00000000000..29361ec9518 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/DataFetcher.java @@ -0,0 +1,16 @@ +package seedu.address.nusmods; + +import java.util.Optional; + +import seedu.address.nusmods.exceptions.NusmodsException; + +public abstract class DataFetcher { + public static final String DATA_FILE_PATH = "data/modules.json"; + public static final String SAVE_DATA_FILE_PATH = "./src/main/resources/data/modules.json"; + public static final String MODULE_SUMMARY_LIST_URL = "https://api.nusmods.com/v2/2020-2021/moduleList.json"; + public static final String MODULE_INFO_URL = "https://api.nusmods.com/v2/2020-2021/modules/%s.json"; + + + abstract void fetchAndSaveModules() throws NusmodsException; + abstract Optional fetchModuleInfo(String moduleCode) throws NusmodsException; +} diff --git a/src/main/java/seedu/address/nusmods/DataFetcherManager.java b/src/main/java/seedu/address/nusmods/DataFetcherManager.java new file mode 100644 index 00000000000..834daa7dae0 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/DataFetcherManager.java @@ -0,0 +1,152 @@ +package seedu.address.nusmods; + +import static seedu.address.nusmods.NusmodsKeywords.MODULE_FILTER_KEYWORDS; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import seedu.address.commons.core.LogsCenter; +import seedu.address.commons.util.HttpUtil; +import seedu.address.commons.util.JsonUtil; +import seedu.address.nusmods.exceptions.NusmodsException; + +/** + * Handles API requests made by GradPad to the NUSMods public API to retrieve module data. + */ +public class DataFetcherManager extends DataFetcher { + private static final Logger logger = LogsCenter.getLogger(DataFetcher.class); + private final HttpUtil httpUtil; + private final String dataFilePath; + + DataFetcherManager() { + httpUtil = HttpUtil.SINGLETON; + dataFilePath = DataFetcher.SAVE_DATA_FILE_PATH; + } + + DataFetcherManager(HttpUtil httpUtil) { + assert(httpUtil != null); + this.httpUtil = httpUtil; + dataFilePath = DataFetcher.SAVE_DATA_FILE_PATH; + } + + DataFetcherManager(HttpUtil httpUtil, String filePath) { + assert(httpUtil != null && !filePath.trim().isEmpty()); + this.httpUtil = httpUtil; + this.dataFilePath = filePath; + } + + /** + * Fetches a list of all NUS module summaries, then fetches module info for all CS modules (only) and + * saves them to a JSON file locally. + * + * @throws NusmodsException if an error occurs while fetching data from NUSMods API or while saving data. + */ + public void fetchAndSaveModules() throws NusmodsException { + List moduleSummaries = fetchModuleSummaryList(); + List filteredModules = filterModuleSummaries(moduleSummaries, MODULE_FILTER_KEYWORDS); + Map moduleInfoMap = generateModuleInfoMap(filteredModules); + + try { + JsonUtil.saveJsonFile(moduleInfoMap, Paths.get(getDataFilePath())); + } catch (IOException ex) { + throw new NusmodsException(ex); + } + } + + /** + * Fetches the module info for a single module from the NUSMods API. + * + * @param moduleCode The module code of the module to fetch data for. + * @return The fetched data in a {@code ModuleInfo} object or {@code Optional.empty()} if data not found. + * @throws NusmodsException if an error occurs while fetching data or if data does not contain valid + * {@code ModuleInfo}. + */ + public Optional fetchModuleInfo(String moduleCode) throws NusmodsException { + assert(!moduleCode.trim().isEmpty()); + logger.info("Fetching module info for: " + moduleCode); + + String jsonResponse = httpUtil.makeGETRequest(String.format(MODULE_INFO_URL, moduleCode)); + try { + return Optional.of(JsonUtil.fromJsonString(jsonResponse, ModuleInfo.class)); + } catch (IOException ex) { + throw new NusmodsException(ex); + } + } + + /** + * Fetches a list of all modules and their summaries from the NUSMods API. + * + * @return A list of {@code ModuleSummary} objects. + * @throws NusmodsException if an error occurs while fetching data or if the data does not contain valid + * {@code ModuleSummary}. + */ + private List fetchModuleSummaryList() throws NusmodsException { + logger.info("Fetching list of module summaries from NUSMods API..."); + + String jsonResponse = httpUtil.makeGETRequest(MODULE_SUMMARY_LIST_URL); + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(jsonResponse, new TypeReference>(){}); + } catch (IOException ex) { + throw new NusmodsException(ex); + } + } + + /** + * Filters a list of {@code ModuleSummary} objects' module codes by a list of keywords. + * + * @param modules The list of ModuleSummary objects to filter. + * @param keywords The keywords to match in each ModuleSummary object's module code. + * @return The filtered list of ModuleSummary objects where every one of their module codes contains any + * one (or more) of the keywords specified. + */ + List filterModuleSummaries(List modules, String... keywords) { + // checks if a module summary's module code contains ANY of the filter keywords + Predicate moduleCodePredicate = module -> Arrays.stream(keywords) + .anyMatch(keyword -> module.getModuleCode().contains(keyword)); + + return modules.stream().filter(moduleCodePredicate).collect(Collectors.toList()); + } + + /** + * Fetches module info for all modules given a list of {@code ModuleSummary} objects, then maps each + * module's code to its {@code ModuleInfo} object. + * + * @param moduleSummaries The list of {@code ModuleSummary} objects to fetch info for. + * @return A mapping of module codes to their respective {@code ModuleInfo}. + */ + Map generateModuleInfoMap(List moduleSummaries) { + logger.info("Fetching module info for all modules..."); + + Map moduleInfoMap = new HashMap<>(); + + for (ModuleSummary summary : moduleSummaries) { + String moduleCode = summary.getModuleCode(); + try { + // delay each API call to adhere to rate limits + Thread.sleep(150); + Optional info = fetchModuleInfo(moduleCode); + info.ifPresent(moduleInfo -> moduleInfoMap.put(moduleCode, moduleInfo)); + } catch (NusmodsException | InterruptedException ex) { + logger.warning("Module info not found for: " + moduleCode); + } + } + + return moduleInfoMap; + } + + public String getDataFilePath() { + return dataFilePath; + } +} diff --git a/src/main/java/seedu/address/nusmods/ModuleInfo.java b/src/main/java/seedu/address/nusmods/ModuleInfo.java new file mode 100644 index 00000000000..879a3b7b999 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/ModuleInfo.java @@ -0,0 +1,106 @@ +package seedu.address.nusmods; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents jackson-friendly module information from NUSMods. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ModuleInfo { + private String moduleCode; + private String title; + private String moduleCredit; + private List semesters = new ArrayList<>(); + private String description; + private String preclusion; + private String prerequisite; + + public String getModuleCode() { + return moduleCode; + } + + public String getTitle() { + return title; + } + + public String getModuleCredit() { + return moduleCredit; + } + + public String getSemesters() { + return semesters.stream().map(Object::toString).map(this::parseSemester).collect(Collectors.joining(", ")); + } + + public String getDescription() { + return description; + } + + public String getPreclusion() { + return preclusion; + } + + public String getPrerequisite() { + return prerequisite; + } + + private String parseSemester(String semester) { + switch (semester) { + case "3": + return "Special Term I"; + case "4": + return "Special Term II"; + default: + return semester; + } + } + + @SuppressWarnings("unchecked") + @JsonProperty("semesterData") + private void unpackNested(List> semesterData) { + for (Map semester : semesterData) { + Object sem = semester.get("semester"); + semesters.add((Integer) sem); + } + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof ModuleInfo)) { + return false; + } + + ModuleInfo otherModuleInfo = (ModuleInfo) other; + return otherModuleInfo.getModuleCode().equals(getModuleCode()) + && otherModuleInfo.getTitle().equals(getTitle()) + && otherModuleInfo.getModuleCredit().equals(getModuleCredit()) + && otherModuleInfo.getSemesters().equals(getSemesters()) + && otherModuleInfo.getDescription().equals(getDescription()) + && equalsIfNotNull(otherModuleInfo.getPreclusion(), getPreclusion()) + && equalsIfNotNull(otherModuleInfo.getPrerequisite(), getPrerequisite()); + } + + private boolean equalsIfNotNull(Object o1, Object o2) { + return o1 == null || o2 == null || o1.equals(o2); + } + + @Override + public int hashCode() { + return Objects.hash(moduleCode, title, moduleCredit, semesters, description, preclusion, prerequisite); + } + + @Override + public String toString() { + return getModuleCode() + " " + getTitle() + " " + getModuleCredit(); + } +} diff --git a/src/main/java/seedu/address/nusmods/ModuleSummary.java b/src/main/java/seedu/address/nusmods/ModuleSummary.java new file mode 100644 index 00000000000..e3032331727 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/ModuleSummary.java @@ -0,0 +1,55 @@ +package seedu.address.nusmods; + + +import java.util.List; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Represents jackson-friendly module summaries from NUSMods. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ModuleSummary { + private String moduleCode; + private String title; + private List semesters; + + public String getModuleCode() { + return moduleCode; + } + + public String getTitle() { + return title; + } + + public List getSemesters() { + return semesters; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + if (!(other instanceof ModuleSummary)) { + return false; + } + + ModuleSummary otherModuleSummary = (ModuleSummary) other; + return otherModuleSummary.getModuleCode().equals(getModuleCode()) + && otherModuleSummary.getTitle().equals(getTitle()) + && otherModuleSummary.getSemesters().equals(getSemesters()); + } + + @Override + public int hashCode() { + return Objects.hash(moduleCode, title, semesters); + } + + @Override + public String toString() { + return getModuleCode() + " " + getTitle() + " " + getSemesters(); + } +} diff --git a/src/main/java/seedu/address/nusmods/NusmodsData.java b/src/main/java/seedu/address/nusmods/NusmodsData.java new file mode 100644 index 00000000000..d78c93a4586 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/NusmodsData.java @@ -0,0 +1,10 @@ +package seedu.address.nusmods; + +import java.util.Optional; + +import seedu.address.nusmods.exceptions.NusmodsException; + +public interface NusmodsData { + Optional getModuleTitle(String moduleCode) throws NusmodsException; + Optional getModuleInfo(String moduleCode) throws NusmodsException; +} diff --git a/src/main/java/seedu/address/nusmods/NusmodsDataManager.java b/src/main/java/seedu/address/nusmods/NusmodsDataManager.java new file mode 100644 index 00000000000..af7f618e8f8 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/NusmodsDataManager.java @@ -0,0 +1,125 @@ +package seedu.address.nusmods; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import seedu.address.nusmods.exceptions.NusmodsException; + +/** + * Encapsulates operations to retrieve NUSMods module information. + */ +public class NusmodsDataManager implements NusmodsData { + private final String filePath; + private final DataFetcher dataFetcher; + + /** + * Default public constructor to create an NusmodsDataManager object. + */ + public NusmodsDataManager() { + dataFetcher = new DataFetcherManager(); + filePath = DataFetcher.DATA_FILE_PATH; + } + + /** + * Constructor to change the DataFetcher class used. Mainly used for testing to provide stubs. + * + * @param dataFetcher The class used to invoke static methods in this class. + */ + NusmodsDataManager(DataFetcher dataFetcher, String filePath) { + assert(dataFetcher != null && !filePath.trim().isEmpty()); + + this.dataFetcher = dataFetcher; + this.filePath = filePath; + } + + + /** + * Returns the module title of a module given its module code. + * + * @param moduleCode The module code to search for. + * @return The module title or {@code Optional.empty()} if not found. + * @throws NusmodsException if an error occurs while retrieving module info. + */ + public Optional getModuleTitle(String moduleCode) throws NusmodsException { + assert(!moduleCode.trim().isEmpty()); + return getModuleInfo(moduleCode).map(ModuleInfo::getTitle); + } + + /** + * Returns the {@code ModuleInfo} of a module given its module code. + * This method attempts to fetch the latest info from the NUSMods API if possible. Otherwise, it will + * still return the info stored locally. + * + * @param moduleCode The module code to search for. + * @return The {@code ModuleInfo} or {@code Optional.empty()} if not found. + * @throws NusmodsException if an error occurs while retrieving module info. + */ + public Optional getModuleInfo(String moduleCode) throws NusmodsException { + assert(!moduleCode.trim().isEmpty()); + + try { + return dataFetcher.fetchModuleInfo(moduleCode); + } catch (NusmodsException ex) { + return getModuleInfoFromFile(moduleCode); + } + } + + /** + * Returns the {@code ModuleInfo} for a given module code by retrieving it locally. + * + * @param moduleCode The module coed to search for. + * @return The {@code ModuleInfo} or {@code Optional.empty()} if not found. + * @throws NusmodsException if an error occurs while retrieving module info. + */ + private Optional getModuleInfoFromFile(String moduleCode) throws NusmodsException { + assert(!moduleCode.trim().isEmpty()); + + ObjectMapper mapper = new ObjectMapper(); + try { + String jsonString = getFileFromResource(getFilePath()); + TypeReference> targetType = new TypeReference<>(){}; + Map moduleInfoMap = mapper.readValue(jsonString, targetType); + + return Optional.ofNullable(moduleInfoMap.get(moduleCode)); + } catch (IOException ex) { + throw new NusmodsException(new IOException("Error reading module info from local file.")); + } + } + + public String getFilePath() { + return filePath; + } + + private String getFileFromResource(String fileName) throws IOException { + + // The class loader that loaded the class + ClassLoader classLoader = getClass().getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(fileName); + + if (inputStream == null) { + throw new IOException(); + } else { + StringBuilder dataString = new StringBuilder(); + + Reader reader = new BufferedReader(new InputStreamReader(inputStream, + Charset.forName(StandardCharsets.UTF_8.name()))); + int c = 0; + while ((c = reader.read()) != -1) { + dataString.append((char) c); + } + + return dataString.toString(); + } + } +} diff --git a/src/main/java/seedu/address/nusmods/NusmodsKeywords.java b/src/main/java/seedu/address/nusmods/NusmodsKeywords.java new file mode 100644 index 00000000000..4ea9e7575cd --- /dev/null +++ b/src/main/java/seedu/address/nusmods/NusmodsKeywords.java @@ -0,0 +1,16 @@ +package seedu.address.nusmods; + +/** + * Class to contain module keywords used by the {@code Nusmods} package. + */ +public final class NusmodsKeywords { + + public static final String[] MODULE_FILTER_KEYWORDS = { + "CS", "CP", "IS1103", "IS4010", "TR3202", "MA1521", "MA1101R", "ST2334", "CM1121", "CM1131", "CM1417", + "LSM1102", "LSM1105", "LSM1106", "LSM1301", "LSM1306", "PC1141", "PC1142", "PC1143", "PC1144" , "PC1221", + "PC1222", "PC1432", "ES2660" + }; + + // make constructor private so that this constant class cannot be instantiated + private NusmodsKeywords() {} +} diff --git a/src/main/java/seedu/address/nusmods/exceptions/NusmodsException.java b/src/main/java/seedu/address/nusmods/exceptions/NusmodsException.java new file mode 100644 index 00000000000..6b8f246d870 --- /dev/null +++ b/src/main/java/seedu/address/nusmods/exceptions/NusmodsException.java @@ -0,0 +1,7 @@ +package seedu.address.nusmods.exceptions; + +public class NusmodsException extends Exception { + public NusmodsException(Exception cause) { + super(cause); + } +} diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java deleted file mode 100644 index 4599182b3f9..00000000000 --- a/src/main/java/seedu/address/storage/AddressBookStorage.java +++ /dev/null @@ -1,45 +0,0 @@ -package seedu.address.storage; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.Optional; - -import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; - -/** - * Represents a storage for {@link seedu.address.model.AddressBook}. - */ -public interface AddressBookStorage { - - /** - * Returns the file path of the data file. - */ - Path getAddressBookFilePath(); - - /** - * Returns AddressBook data as a {@link ReadOnlyAddressBook}. - * Returns {@code Optional.empty()} if storage file is not found. - * @throws DataConversionException if the data in storage is not in the expected format. - * @throws IOException if there was any problem when reading from the storage. - */ - Optional readAddressBook() throws DataConversionException, IOException; - - /** - * @see #getAddressBookFilePath() - */ - Optional readAddressBook(Path filePath) throws DataConversionException, IOException; - - /** - * Saves the given {@link ReadOnlyAddressBook} to the storage. - * @param addressBook cannot be null. - * @throws IOException if there was any problem writing to the file. - */ - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; - - /** - * @see #saveAddressBook(ReadOnlyAddressBook) - */ - void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException; - -} diff --git a/src/main/java/seedu/address/storage/GemCommandPaths.java b/src/main/java/seedu/address/storage/GemCommandPaths.java new file mode 100644 index 00000000000..2358e598b9a --- /dev/null +++ b/src/main/java/seedu/address/storage/GemCommandPaths.java @@ -0,0 +1,12 @@ +package seedu.address.storage; + +public class GemCommandPaths { + public static final String GEH_SEM1_PATH = "data/GEM/GEHsem1.json"; + public static final String GEH_SEM2_PATH = "data/GEM/GEHsem2.json"; + public static final String GEQ_PATH = "data/GEM/GEQ.json"; + public static final String GER_PATH = "data/GEM/GER.json"; + public static final String GES_SEM1_PATH = "data/GEM/GESsem1.json"; + public static final String GES_SEM2_PATH = "data/GEM/GESsem2.json"; + public static final String GET_SEM1_PATH = "data/GEM/GETsem1.json"; + public static final String GET_SEM2_PATH = "data/GEM/GETsem2.json"; +} diff --git a/src/main/java/seedu/address/storage/GemCommandStorage.java b/src/main/java/seedu/address/storage/GemCommandStorage.java new file mode 100644 index 00000000000..e471736077b --- /dev/null +++ b/src/main/java/seedu/address/storage/GemCommandStorage.java @@ -0,0 +1,162 @@ +package seedu.address.storage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import javafx.collections.ObservableList; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.commons.util.JsonUtil; +import seedu.address.model.module.Module; + +public class GemCommandStorage { + private ObservableList gehModules; + private ObservableList geqModules; + private ObservableList gerModules; + private ObservableList gesModules; + private ObservableList getModules; + + /** + * Makes use of classLoaders to convert the original file path + * into one that can be readable during runtime, such that it + * can be used to retrieve the File's content. + * + * @param filePath Original file path. + * @return Converted file content of type String. + * @throws IOException When the provided fileName is invalid. + */ + private String getFileFromResource(String filePath) throws IOException { + // The class loader that loaded the class + ClassLoader classLoader = getClass().getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(filePath); + + if (inputStream == null) { + throw new IOException(); + } else { + StringBuilder dataString = new StringBuilder(); + + Reader reader = new BufferedReader(new InputStreamReader(inputStream, + Charset.forName(StandardCharsets.UTF_8.name()))); + int c = 0; + while ((c = reader.read()) != -1) { + dataString.append((char) c); + } + + return dataString.toString(); + } + } + + /** + * Returns gehModules attribute of GemCommandStorage object. + * + * @return gehModules attribute of type ObservableList. + */ + public ObservableList getGehModules() { + return gehModules; + } + + /** + * Loads the gehModules attribute with GEH Modules. + * + * @param path Path of the GEH Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setGehModules(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + gehModules = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns geqModules attribute of GemCommandStorage object. + * + * @return geqModules attribute of type ObservableList. + */ + public ObservableList getGeqModules() { + return geqModules; + } + + /** + * Loads the geqModules attribute with GEQ Modules. + * + * @param path Path of the GEQ Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setGeqModules(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + geqModules = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns gerModules attribute of GemCommandStorage object. + * + * @return gerModules attribute of type ObservableList. + */ + public ObservableList getGerModules() { + return gerModules; + } + + /** + * Loads the gerModules attribute with GER Modules. + * + * @param path Path of the GER Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setGerModules(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + gerModules = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns gesModules attribute of GemCommandStorage object. + * + * @return gesModules attribute of type ObservableList. + */ + public ObservableList getGesModules() { + return gesModules; + } + + /** + * Loads the gesModules attribute with GES Modules. + * + * @param path Path of the GES Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setGesModules(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + gesModules = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns getModules attribute of GemCommandStorage object. + * + * @return getModules attribute of type ObservableList. + */ + public ObservableList getGetModules() { + return getModules; + } + + /** + * Loads the getModules attribute with GET Modules. + * + * @param path Path of the GET Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setGetModules(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + getModules = JsonUtil.getModulesFromJsonFile(file); + } +} diff --git a/src/main/java/seedu/address/storage/GradPadStorage.java b/src/main/java/seedu/address/storage/GradPadStorage.java new file mode 100644 index 00000000000..a5fec039bd5 --- /dev/null +++ b/src/main/java/seedu/address/storage/GradPadStorage.java @@ -0,0 +1,48 @@ +package seedu.address.storage; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.model.GradPad; +import seedu.address.model.ReadOnlyGradPad; + +/** + * Represents a storage for {@link GradPad}. + */ +public interface GradPadStorage { + + /** + * Returns the file path of the data file. + */ + Path getGradPadFilePath(); + + /** + * Returns GradPad data as a {@link ReadOnlyGradPad}. + * Returns {@code Optional.empty()} if storage file is not found. + * + * @throws DataConversionException if the data in storage is not in the expected format. + * @throws IOException if there was any problem when reading from the storage. + */ + Optional readGradPad() throws DataConversionException, IOException; + + /** + * @see #getGradPadFilePath() + */ + Optional readGradPad(Path filePath) throws DataConversionException, IOException; + + /** + * Saves the given {@link ReadOnlyGradPad} to the storage. + * + * @param gradPad cannot be null. + * @throws IOException if there was any problem writing to the file. + */ + void saveGradPad(ReadOnlyGradPad gradPad) throws IOException; + + /** + * @see #saveGradPad(ReadOnlyGradPad) + */ + void saveGradPad(ReadOnlyGradPad gradPad, Path filePath) throws IOException; + +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedModule.java b/src/main/java/seedu/address/storage/JsonAdaptedModule.java new file mode 100644 index 00000000000..5df199d4fb4 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedModule.java @@ -0,0 +1,96 @@ +package seedu.address.storage; + +import static seedu.address.commons.core.Messages.MESSAGE_CONSTRAINTS_CODE; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.module.ModularCredits; +import seedu.address.model.module.Module; +import seedu.address.model.module.ModuleCode; +import seedu.address.model.module.ModuleTitle; +import seedu.address.model.tag.Tag; + +/** + * Jackson-friendly version of {@link Module}. + */ +class JsonAdaptedModule { + + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Module's %s field is missing!"; + + private final String code; + private final String title; + private final String credits; + private final List tagged = new ArrayList<>(); + + /** + * Constructs a {@code JsonAdaptedModule} with the given module details. + */ + @JsonCreator + public JsonAdaptedModule(@JsonProperty("moduleCode") String code, + @JsonProperty("moduleTitle") String title, + @JsonProperty("modularCredits") String credits, + @JsonProperty("tagged") List tagged) { + this.code = code; + this.title = title; + this.credits = credits; + if (tagged != null) { + this.tagged.addAll(tagged); + } + } + + /** + * Converts a given {@code Module} into this class for Jackson use. + */ + public JsonAdaptedModule(Module source) { + code = source.getModuleCode().toString(); + title = source.getModuleTitle().toString(); + credits = source.getModularCredits().value; + tagged.addAll(source.getTags().stream() + .map(JsonAdaptedTag::new) + .collect(Collectors.toList())); + } + + /** + * Converts this Jackson-friendly adapted module object into the model's {@code Module} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted module. + */ + public Module toModelType() throws IllegalValueException { + final List moduleTags = new ArrayList<>(); + for (JsonAdaptedTag tag : tagged) { + moduleTags.add(tag.toModelType()); + } + + if (code == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ModuleCode.class.getSimpleName())); + } + if (!ModuleCode.isValidModuleCode(code)) { + throw new IllegalValueException(MESSAGE_CONSTRAINTS_CODE); + } + final ModuleCode modelCode = new ModuleCode(code); + + if (title == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ModuleTitle.class.getSimpleName())); + } + final ModuleTitle moduleTitle = new ModuleTitle(title); + + if (credits == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + ModularCredits.class.getSimpleName())); + } + final ModularCredits modelCredits = new ModularCredits(credits); + + final Set modelTags = new HashSet<>(moduleTags); + return new Module(modelCode, moduleTitle, modelCredits, modelTags); + } +} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java deleted file mode 100644 index a6321cec2ea..00000000000 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ /dev/null @@ -1,109 +0,0 @@ -package seedu.address.storage; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.person.Address; -import seedu.address.model.person.Email; -import seedu.address.model.person.Name; -import seedu.address.model.person.Person; -import seedu.address.model.person.Phone; -import seedu.address.model.tag.Tag; - -/** - * Jackson-friendly version of {@link Person}. - */ -class JsonAdaptedPerson { - - public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!"; - - private final String name; - private final String phone; - private final String email; - private final String address; - private final List tagged = new ArrayList<>(); - - /** - * Constructs a {@code JsonAdaptedPerson} with the given person details. - */ - @JsonCreator - public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone, - @JsonProperty("email") String email, @JsonProperty("address") String address, - @JsonProperty("tagged") List tagged) { - this.name = name; - this.phone = phone; - this.email = email; - this.address = address; - if (tagged != null) { - this.tagged.addAll(tagged); - } - } - - /** - * Converts a given {@code Person} into this class for Jackson use. - */ - public JsonAdaptedPerson(Person source) { - name = source.getName().fullName; - phone = source.getPhone().value; - email = source.getEmail().value; - address = source.getAddress().value; - tagged.addAll(source.getTags().stream() - .map(JsonAdaptedTag::new) - .collect(Collectors.toList())); - } - - /** - * Converts this Jackson-friendly adapted person object into the model's {@code Person} object. - * - * @throws IllegalValueException if there were any data constraints violated in the adapted person. - */ - public Person toModelType() throws IllegalValueException { - final List personTags = new ArrayList<>(); - for (JsonAdaptedTag tag : tagged) { - personTags.add(tag.toModelType()); - } - - if (name == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName())); - } - if (!Name.isValidName(name)) { - throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS); - } - final Name modelName = new Name(name); - - if (phone == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName())); - } - if (!Phone.isValidPhone(phone)) { - throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS); - } - final Phone modelPhone = new Phone(phone); - - if (email == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName())); - } - if (!Email.isValidEmail(email)) { - throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS); - } - final Email modelEmail = new Email(email); - - if (address == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName())); - } - if (!Address.isValidAddress(address)) { - throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS); - } - final Address modelAddress = new Address(address); - - final Set modelTags = new HashSet<>(personTags); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags); - } - -} diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java index 0df22bdb754..2d261f44dfa 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedTag.java @@ -1,5 +1,7 @@ package seedu.address.storage; +import static seedu.address.commons.core.Messages.MESSAGE_CONSTRAINTS_TAG; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; @@ -40,7 +42,7 @@ public String getTagName() { */ public Tag toModelType() throws IllegalValueException { if (!Tag.isValidTagName(tagName)) { - throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS); + throw new IllegalValueException(MESSAGE_CONSTRAINTS_TAG); } return new Tag(tagName); } diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonGradPadStorage.java similarity index 50% rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java rename to src/main/java/seedu/address/storage/JsonGradPadStorage.java index dfab9daaa0d..ea8b174a867 100644 --- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java +++ b/src/main/java/seedu/address/storage/JsonGradPadStorage.java @@ -12,47 +12,47 @@ import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.commons.util.FileUtil; import seedu.address.commons.util.JsonUtil; -import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.ReadOnlyGradPad; /** - * A class to access AddressBook data stored as a json file on the hard disk. + * A class to access GradPad data stored as a json file on the hard disk. */ -public class JsonAddressBookStorage implements AddressBookStorage { +public class JsonGradPadStorage implements GradPadStorage { - private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class); + private static final Logger logger = LogsCenter.getLogger(JsonGradPadStorage.class); private Path filePath; - public JsonAddressBookStorage(Path filePath) { + public JsonGradPadStorage(Path filePath) { this.filePath = filePath; } - public Path getAddressBookFilePath() { + public Path getGradPadFilePath() { return filePath; } @Override - public Optional readAddressBook() throws DataConversionException { - return readAddressBook(filePath); + public Optional readGradPad() throws DataConversionException { + return readGradPad(filePath); } /** - * Similar to {@link #readAddressBook()}. + * Similar to {@link #readGradPad()}. * * @param filePath location of the data. Cannot be null. * @throws DataConversionException if the file is not in the correct format. */ - public Optional readAddressBook(Path filePath) throws DataConversionException { + public Optional readGradPad(Path filePath) throws DataConversionException { requireNonNull(filePath); - Optional jsonAddressBook = JsonUtil.readJsonFile( - filePath, JsonSerializableAddressBook.class); - if (!jsonAddressBook.isPresent()) { + Optional jsonGradPad = JsonUtil.readJsonFile( + filePath, JsonSerializableGradPad.class); + if (!jsonGradPad.isPresent()) { return Optional.empty(); } try { - return Optional.of(jsonAddressBook.get().toModelType()); + return Optional.of(jsonGradPad.get().toModelType()); } catch (IllegalValueException ive) { logger.info("Illegal values found in " + filePath + ": " + ive.getMessage()); throw new DataConversionException(ive); @@ -60,21 +60,21 @@ public Optional readAddressBook(Path filePath) throws DataC } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { - saveAddressBook(addressBook, filePath); + public void saveGradPad(ReadOnlyGradPad gradPad) throws IOException { + saveGradPad(gradPad, filePath); } /** - * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}. + * Similar to {@link #saveGradPad(ReadOnlyGradPad)}. * * @param filePath location of the data. Cannot be null. */ - public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException { - requireNonNull(addressBook); + public void saveGradPad(ReadOnlyGradPad gradPad, Path filePath) throws IOException { + requireNonNull(gradPad); requireNonNull(filePath); FileUtil.createIfMissing(filePath); - JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath); + JsonUtil.saveJsonFile(new JsonSerializableGradPad(gradPad), filePath); } } diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java deleted file mode 100644 index 5efd834091d..00000000000 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ /dev/null @@ -1,60 +0,0 @@ -package seedu.address.storage; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonRootName; - -import seedu.address.commons.exceptions.IllegalValueException; -import seedu.address.model.AddressBook; -import seedu.address.model.ReadOnlyAddressBook; -import seedu.address.model.person.Person; - -/** - * An Immutable AddressBook that is serializable to JSON format. - */ -@JsonRootName(value = "addressbook") -class JsonSerializableAddressBook { - - public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; - - private final List persons = new ArrayList<>(); - - /** - * Constructs a {@code JsonSerializableAddressBook} with the given persons. - */ - @JsonCreator - public JsonSerializableAddressBook(@JsonProperty("persons") List persons) { - this.persons.addAll(persons); - } - - /** - * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use. - * - * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}. - */ - public JsonSerializableAddressBook(ReadOnlyAddressBook source) { - persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList())); - } - - /** - * Converts this address book into the model's {@code AddressBook} object. - * - * @throws IllegalValueException if there were any data constraints violated. - */ - public AddressBook toModelType() throws IllegalValueException { - AddressBook addressBook = new AddressBook(); - for (JsonAdaptedPerson jsonAdaptedPerson : persons) { - Person person = jsonAdaptedPerson.toModelType(); - if (addressBook.hasPerson(person)) { - throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON); - } - addressBook.addPerson(person); - } - return addressBook; - } - -} diff --git a/src/main/java/seedu/address/storage/JsonSerializableGradPad.java b/src/main/java/seedu/address/storage/JsonSerializableGradPad.java new file mode 100644 index 00000000000..4a74bfee5c3 --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonSerializableGradPad.java @@ -0,0 +1,60 @@ +package seedu.address.storage; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRootName; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.GradPad; +import seedu.address.model.ReadOnlyGradPad; +import seedu.address.model.module.Module; + +/** + * An Immutable GradPad that is serializable to JSON format. + */ +@JsonRootName(value = "gradpad") +public class JsonSerializableGradPad { + + public static final String MESSAGE_DUPLICATE_MODULE = "Modules list contains duplicate module(s)."; + + private final List modules = new ArrayList<>(); + + /** + * Constructs a {@code JsonSerializableGradPad} with the given modules. + */ + @JsonCreator + public JsonSerializableGradPad(@JsonProperty("modules") List modules) { + this.modules.addAll(modules); + } + + /** + * Converts a given {@code ReadOnlyGradPad} into this class for Jackson use. + * + * @param source future changes to this will not affect the created {@code JsonSerializableGradPad}. + */ + public JsonSerializableGradPad(ReadOnlyGradPad source) { + modules.addAll(source.getModuleList().stream().map(JsonAdaptedModule::new).collect(Collectors.toList())); + } + + /** + * Converts this GradPad into the model's {@code GradPad} object. + * + * @throws IllegalValueException if there were any data constraints violated. + */ + public GradPad toModelType() throws IllegalValueException { + GradPad gradPad = new GradPad(); + for (JsonAdaptedModule jsonAdaptedModule : modules) { + Module module = jsonAdaptedModule.toModelType(); + if (gradPad.hasModule(module)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_MODULE); + } + gradPad.addModule(module); + } + return gradPad; + } + +} diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java index bc2bbad84aa..d86afed2056 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java @@ -32,6 +32,7 @@ public Optional readUserPrefs() throws DataConversionException { /** * Similar to {@link #readUserPrefs()} + * * @param prefsFilePath location of the data. Cannot be null. * @throws DataConversionException if the file format is not as expected. */ diff --git a/src/main/java/seedu/address/storage/RequiredCommandMessages.java b/src/main/java/seedu/address/storage/RequiredCommandMessages.java new file mode 100644 index 00000000000..7be7d007c18 --- /dev/null +++ b/src/main/java/seedu/address/storage/RequiredCommandMessages.java @@ -0,0 +1,27 @@ +package seedu.address.storage; + +public class RequiredCommandMessages { + public static final String MESSAGE_FOUNDATION = "These are the Foundation Modules you have yet to take: "; + public static final String MESSAGE_FAILURE = "There was an error loading the Modules :("; + public static final String MESSAGE_SCIENCE = "You have not completed your Science Module requirement," + + " use the 'science' command to view the available modules."; + public static final String MESSAGE_INTERN_1 = "You have yet to complete your 12MCs worth of Internship Modules."; + public static final String MESSAGE_INTERN_2 = "These are the Internship Modules you can take:"; + public static final String MESSAGE_SUCCESS_FOUNDATION = "You have completed all your Foundation Modules!"; + public static final String MESSAGE_SUCCESS_SCIENCE = "You have completed your Science Module Requirement!"; + public static final String MESSAGE_SUCCESS_INTERN = "You have completed your Internship Module Requirement!"; + public static final String MESSAGE_ITPROF = "These are the IT Professionalism Modules you have yet to take:"; + public static final String MESSAGE_SUCCESS_ITPROF = "You have completed your " + + "IT Professionalism Module Requirement!"; + public static final String MESSAGE_MATH = "These are the Math Modules you have yet to take:"; + public static final String MESSAGE_SUCCESS_MATH = "You have completed your Math Module Requirement!"; + public static final String MESSAGE_SUCCESS_GE = "You have completed all your GEM requirements!"; + public static final String MESSAGE_FAILURE_GE_1 = "You have not completed the following GEM requirements:"; + public static final String MESSAGE_FAILURE_GE_2 = "Use the 'gem' command to view all the available modules."; + public static final String FOUNDATION_PATH = "data/foundationmodules.json"; + public static final String INTERNSHIP_PATH = "data/industrialexperience.json"; + public static final String ITPROF_PATH = "data/ITProfessionalism.json"; + public static final String MATH_PATH = "data/mathmodules.json"; + public static final String SCIENCE_PATH = "data/sciencemodules.json"; + public static final String PRECLUSION_PATH = "data/precludedmodules.json"; +} diff --git a/src/main/java/seedu/address/storage/RequiredCommandStorage.java b/src/main/java/seedu/address/storage/RequiredCommandStorage.java new file mode 100644 index 00000000000..4d7cfaa02ff --- /dev/null +++ b/src/main/java/seedu/address/storage/RequiredCommandStorage.java @@ -0,0 +1,180 @@ +package seedu.address.storage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import javafx.collections.ObservableList; +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.commons.util.JsonUtil; +import seedu.address.model.module.Module; + +public class RequiredCommandStorage { + private ObservableList requiredFoundation; + private ObservableList requiredITprof; + private ObservableList requiredMath; + private ObservableList requiredScience; + private ObservableList requiredInternship; + private Map preclusionMap; + + /** + * Makes use of classLoaders to convert the original file path + * into one that can be readable during runtime, such that it + * can be used to retrieve the File's content. + * + * @param filePath Original file path. + * @return Converted file content of type String. + * @throws IOException When the provided fileName is invalid. + */ + private String getFileFromResource(String filePath) throws IOException { + // The class loader that loaded the class + ClassLoader classLoader = getClass().getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(filePath); + + if (inputStream == null) { + throw new IOException(); + } else { + StringBuilder dataString = new StringBuilder(); + + Reader reader = new BufferedReader(new InputStreamReader(inputStream, + Charset.forName(StandardCharsets.UTF_8.name()))); + int c = 0; + while ((c = reader.read()) != -1) { + dataString.append((char) c); + } + + return dataString.toString(); + } + } + + /** + * Returns preclusionMap attribute of RequiredCommandStorage object. + * + * @return preclusionMap attribute of type Map. + */ + public Map getPreclusionMap() { + return preclusionMap; + } + + /** + * Loads the preclusionMap attribute with Precluded Modules. + * + * @param path Path of the Precluded Modules file. + * @throws IOException When path is invalid. + */ + public void setPreclusionMap(String path) throws IOException { + String file = getFileFromResource(path); + preclusionMap = JsonUtil.getPreclusionMapFromJsonFile(file); + } + + /** + * Returns requiredFoundation attribute of RequiredCommandStorage object. + * + * @return requiredFoundation attribute of type ObservableList. + */ + public ObservableList getRequiredFoundation() { + return requiredFoundation; + } + /** + * Loads the requiredFoundation attribute with Foundation Modules. + * + * @param path Path of the Foundation Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setRequiredFoundation(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + requiredFoundation = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns requiredITprof attribute of RequiredCommandStorage object. + * + * @return requiredITprof attribute of type ObservableList. + */ + public ObservableList getRequiredITprof() { + return requiredITprof; + } + /** + * Loads the requiredITprof attribute with IT Professionalism Modules. + * + * @param path Path of the IT Professionalism Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setRequiredITprof(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + requiredITprof = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns requiredMath attribute of RequiredCommandStorage object. + * + * @return requiredMath attribute of type ObservableList. + */ + public ObservableList getRequiredMath() { + return requiredMath; + } + /** + * Loads the requiredMath attribute with Math Modules. + * + * @param path Path of the Math Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setRequiredMath(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + requiredMath = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns requiredScience attribute of RequiredCommandStorage object. + * + * @return requiredScience attribute of type ObservableList. + */ + public ObservableList getRequiredScience() { + return requiredScience; + } + /** + * Loads the requiredScience attribute with Science Modules. + * + * @param path Path of the Science Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setRequiredScience(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + requiredScience = JsonUtil.getModulesFromJsonFile(file); + } + + /** + * Returns requiredInternship attribute of RequiredCommandStorage object. + * + * @return requiredInternship attribute of type ObservableList. + */ + public ObservableList getRequiredInternship() { + return requiredInternship; + } + /** + * Loads the requiredInternship attribute with Internship Modules. + * + * @param path Path of the Internship Modules file. + * @throws IOException When path is invalid. + * @throws IllegalValueException When the data from the JSON file does not match the + * specific field headers of the JsonAdaptedModule class (Eg.'moduleCode', 'modularCredits'). + */ + public void setRequiredInternship(String path) throws IOException, IllegalValueException { + String file = getFileFromResource(path); + requiredInternship = JsonUtil.getModulesFromJsonFile(file); + } +} + diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java index beda8bd9f11..81c03114044 100644 --- a/src/main/java/seedu/address/storage/Storage.java +++ b/src/main/java/seedu/address/storage/Storage.java @@ -5,14 +5,14 @@ import java.util.Optional; import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.ReadOnlyGradPad; import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.UserPrefs; /** * API of the Storage component */ -public interface Storage extends AddressBookStorage, UserPrefsStorage { +public interface Storage extends GradPadStorage, UserPrefsStorage { @Override Optional readUserPrefs() throws DataConversionException, IOException; @@ -21,12 +21,12 @@ public interface Storage extends AddressBookStorage, UserPrefsStorage { void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException; @Override - Path getAddressBookFilePath(); + Path getGradPadFilePath(); @Override - Optional readAddressBook() throws DataConversionException, IOException; + Optional readGradPad() throws DataConversionException, IOException; @Override - void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException; + void saveGradPad(ReadOnlyGradPad gradPad) throws IOException; } diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java index 79868290974..8e14cea7ce7 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/seedu/address/storage/StorageManager.java @@ -7,25 +7,26 @@ import seedu.address.commons.core.LogsCenter; import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.model.ReadOnlyAddressBook; +import seedu.address.model.ReadOnlyGradPad; import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.UserPrefs; /** - * Manages storage of AddressBook data in local storage. + * Manages storage of GradPad data in local storage. */ public class StorageManager implements Storage { private static final Logger logger = LogsCenter.getLogger(StorageManager.class); - private AddressBookStorage addressBookStorage; + private GradPadStorage gradPadStorage; private UserPrefsStorage userPrefsStorage; /** - * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}. + * Creates a {@code StorageManager} with the given {@code GradPadStorage} and {@code UserPrefStorage}. */ - public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) { + public StorageManager(GradPadStorage gradPadStorage, UserPrefsStorage userPrefsStorage) { super(); - this.addressBookStorage = addressBookStorage; + assert(gradPadStorage != null && userPrefsStorage != null); + this.gradPadStorage = gradPadStorage; this.userPrefsStorage = userPrefsStorage; } @@ -47,33 +48,33 @@ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException { } - // ================ AddressBook methods ============================== + // ================ GradPad methods ============================== @Override - public Path getAddressBookFilePath() { - return addressBookStorage.getAddressBookFilePath(); + public Path getGradPadFilePath() { + return gradPadStorage.getGradPadFilePath(); } @Override - public Optional readAddressBook() throws DataConversionException, IOException { - return readAddressBook(addressBookStorage.getAddressBookFilePath()); + public Optional readGradPad() throws DataConversionException, IOException { + return readGradPad(gradPadStorage.getGradPadFilePath()); } @Override - public Optional readAddressBook(Path filePath) throws DataConversionException, IOException { + public Optional readGradPad(Path filePath) throws DataConversionException, IOException { logger.fine("Attempting to read data from file: " + filePath); - return addressBookStorage.readAddressBook(filePath); + return gradPadStorage.readGradPad(filePath); } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException { - saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath()); + public void saveGradPad(ReadOnlyGradPad gradPad) throws IOException { + saveGradPad(gradPad, gradPadStorage.getGradPadFilePath()); } @Override - public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException { + public void saveGradPad(ReadOnlyGradPad gradPad, Path filePath) throws IOException { logger.fine("Attempting to write to data file: " + filePath); - addressBookStorage.saveAddressBook(addressBook, filePath); + gradPadStorage.saveGradPad(gradPad, filePath); } } diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/address/storage/UserPrefsStorage.java index 29eef178dbc..1eb07ff2880 100644 --- a/src/main/java/seedu/address/storage/UserPrefsStorage.java +++ b/src/main/java/seedu/address/storage/UserPrefsStorage.java @@ -20,7 +20,8 @@ public interface UserPrefsStorage { /** * Returns UserPrefs data from storage. - * Returns {@code Optional.empty()} if storage file is not found. + * Returns {@code Optional.empty()} if storage file is not found. + * * @throws DataConversionException if the data in storage is not in the expected format. * @throws IOException if there was any problem when reading from the storage. */ @@ -28,6 +29,7 @@ public interface UserPrefsStorage { /** * Saves the given {@link seedu.address.model.ReadOnlyUserPrefs} to the storage. + * * @param userPrefs cannot be null. * @throws IOException if there was any problem writing to the file. */ diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java deleted file mode 100644 index 9a665915949..00000000000 --- a/src/main/java/seedu/address/ui/HelpWindow.java +++ /dev/null @@ -1,102 +0,0 @@ -package seedu.address.ui; - -import java.util.logging.Logger; - -import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import javafx.stage.Stage; -import seedu.address.commons.core.LogsCenter; - -/** - * Controller for a help page - */ -public class HelpWindow extends UiPart { - - public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html"; - public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL; - - private static final Logger logger = LogsCenter.getLogger(HelpWindow.class); - private static final String FXML = "HelpWindow.fxml"; - - @FXML - private Button copyButton; - - @FXML - private Label helpMessage; - - /** - * Creates a new HelpWindow. - * - * @param root Stage to use as the root of the HelpWindow. - */ - public HelpWindow(Stage root) { - super(FXML, root); - helpMessage.setText(HELP_MESSAGE); - } - - /** - * Creates a new HelpWindow. - */ - public HelpWindow() { - this(new Stage()); - } - - /** - * Shows the help window. - * @throws IllegalStateException - *
    - *
  • - * if this method is called on a thread other than the JavaFX Application Thread. - *
  • - *
  • - * if this method is called during animation or layout processing. - *
  • - *
  • - * if this method is called on the primary stage. - *
  • - *
  • - * if {@code dialogStage} is already showing. - *
  • - *
- */ - public void show() { - logger.fine("Showing help page about the application."); - getRoot().show(); - getRoot().centerOnScreen(); - } - - /** - * Returns true if the help window is currently being shown. - */ - public boolean isShowing() { - return getRoot().isShowing(); - } - - /** - * Hides the help window. - */ - public void hide() { - getRoot().hide(); - } - - /** - * Focuses on the help window. - */ - public void focus() { - getRoot().requestFocus(); - } - - /** - * Copies the URL to the user guide to the clipboard. - */ - @FXML - private void copyUrl() { - final Clipboard clipboard = Clipboard.getSystemClipboard(); - final ClipboardContent url = new ClipboardContent(); - url.putString(USERGUIDE_URL); - clipboard.setContent(url); - } -} diff --git a/src/main/java/seedu/address/ui/IntroDisplay.java b/src/main/java/seedu/address/ui/IntroDisplay.java new file mode 100644 index 00000000000..b8f7a0599f3 --- /dev/null +++ b/src/main/java/seedu/address/ui/IntroDisplay.java @@ -0,0 +1,36 @@ +package seedu.address.ui; + +import javafx.scene.layout.Region; + +/** + * A ui component for displaying the opening page of GradPad. + */ +public class IntroDisplay extends UiPart { + + private static final String FXML = "IntroDisplay.fxml"; + + public IntroDisplay() { + super(FXML); + } + + /** + * Returns true if the intro display is currently being shown. + */ + public boolean isShowing() { + return getRoot().isVisible(); + } + + /** + * Hides the intro display. + */ + public void hide() { + getRoot().setVisible(false); + } + + /** + * Shows the intro display. + */ + public void show() { + getRoot().setVisible(true); + } +} diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 9106c3aa6e5..292ba42b7a3 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -2,14 +2,12 @@ import java.util.logging.Logger; -import javafx.event.ActionEvent; +import javafx.animation.PauseTransition; +import javafx.application.Platform; import javafx.fxml.FXML; -import javafx.scene.control.MenuItem; -import javafx.scene.control.TextInputControl; -import javafx.scene.input.KeyCombination; -import javafx.scene.input.KeyEvent; import javafx.scene.layout.StackPane; import javafx.stage.Stage; +import javafx.util.Duration; import seedu.address.commons.core.GuiSettings; import seedu.address.commons.core.LogsCenter; import seedu.address.logic.Logic; @@ -31,18 +29,15 @@ public class MainWindow extends UiPart { private Logic logic; // Independent Ui parts residing in this Ui container - private PersonListPanel personListPanel; + private ModuleListPanel moduleListPanel; private ResultDisplay resultDisplay; - private HelpWindow helpWindow; + private IntroDisplay introDisplay; @FXML private StackPane commandBoxPlaceholder; @FXML - private MenuItem helpMenuItem; - - @FXML - private StackPane personListPanelPlaceholder; + private StackPane moduleListPanelPlaceholder; @FXML private StackPane resultDisplayPlaceholder; @@ -62,61 +57,26 @@ public MainWindow(Stage primaryStage, Logic logic) { // Configure the UI setWindowDefaultSize(logic.getGuiSettings()); - - setAccelerators(); - - helpWindow = new HelpWindow(); } public Stage getPrimaryStage() { return primaryStage; } - private void setAccelerators() { - setAccelerator(helpMenuItem, KeyCombination.valueOf("F1")); - } - - /** - * Sets the accelerator of a MenuItem. - * @param keyCombination the KeyCombination value of the accelerator - */ - private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) { - menuItem.setAccelerator(keyCombination); - - /* - * TODO: the code below can be removed once the bug reported here - * https://bugs.openjdk.java.net/browse/JDK-8131666 - * is fixed in later version of SDK. - * - * According to the bug report, TextInputControl (TextField, TextArea) will - * consume function-key events. Because CommandBox contains a TextField, and - * ResultDisplay contains a TextArea, thus some accelerators (e.g F1) will - * not work when the focus is in them because the key event is consumed by - * the TextInputControl(s). - * - * For now, we add following event filter to capture such key events and open - * help window purposely so to support accelerators even when focus is - * in CommandBox or ResultDisplay. - */ - getRoot().addEventFilter(KeyEvent.KEY_PRESSED, event -> { - if (event.getTarget() instanceof TextInputControl && keyCombination.match(event)) { - menuItem.getOnAction().handle(new ActionEvent()); - event.consume(); - } - }); - } - /** * Fills up all the placeholders of this window. */ void fillInnerParts() { - personListPanel = new PersonListPanel(logic.getFilteredPersonList()); - personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + moduleListPanel = new ModuleListPanel(logic.getFilteredModuleList()); + moduleListPanelPlaceholder.getChildren().add(moduleListPanel.getRoot()); + introDisplay = new IntroDisplay(); resultDisplay = new ResultDisplay(); + resultDisplay.hide(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); + resultDisplayPlaceholder.getChildren().add(introDisplay.getRoot()); - StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath()); + StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getGradPadFilePath()); statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot()); CommandBox commandBox = new CommandBox(this::executeCommand); @@ -135,18 +95,6 @@ private void setWindowDefaultSize(GuiSettings guiSettings) { } } - /** - * Opens the help window or focuses on it if it's already opened. - */ - @FXML - public void handleHelp() { - if (!helpWindow.isShowing()) { - helpWindow.show(); - } else { - helpWindow.focus(); - } - } - void show() { primaryStage.show(); } @@ -159,12 +107,9 @@ private void handleExit() { GuiSettings guiSettings = new GuiSettings(primaryStage.getWidth(), primaryStage.getHeight(), (int) primaryStage.getX(), (int) primaryStage.getY()); logic.setGuiSettings(guiSettings); - helpWindow.hide(); - primaryStage.hide(); - } - - public PersonListPanel getPersonListPanel() { - return personListPanel; + PauseTransition delay = new PauseTransition(Duration.seconds(1.5)); + delay.setOnFinished(event -> Platform.exit()); + delay.play(); } /** @@ -174,14 +119,15 @@ public PersonListPanel getPersonListPanel() { */ private CommandResult executeCommand(String commandText) throws CommandException, ParseException { try { - CommandResult commandResult = logic.execute(commandText); + if (introDisplay.isShowing()) { + introDisplay.hide(); + resultDisplay.show(); + } + + CommandResult commandResult = logic.execute(commandText.trim().replaceAll("\\s+", " ")); logger.info("Result: " + commandResult.getFeedbackToUser()); resultDisplay.setFeedbackToUser(commandResult.getFeedbackToUser()); - if (commandResult.isShowHelp()) { - handleHelp(); - } - if (commandResult.isExit()) { handleExit(); } diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/ModuleCard.java similarity index 57% rename from src/main/java/seedu/address/ui/PersonCard.java rename to src/main/java/seedu/address/ui/ModuleCard.java index 7fc927bc5d9..4a75cac842c 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/ModuleCard.java @@ -7,52 +7,49 @@ import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; -import seedu.address.model.person.Person; +import seedu.address.model.module.Module; /** - * An UI component that displays information of a {@code Person}. + * An UI component that displays information of a {@code Module}. */ -public class PersonCard extends UiPart { +public class ModuleCard extends UiPart { - private static final String FXML = "PersonListCard.fxml"; + private static final String FXML = "ModuleListCard.fxml"; /** * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. * As a consequence, UI elements' variable names cannot be set to such keywords * or an exception will be thrown by JavaFX during runtime. * - * @see The issue on AddressBook level 4 + * @see The issue on GradPad level 4 */ - public final Person person; + public final Module module; @FXML private HBox cardPane; @FXML - private Label name; + private Label code; @FXML private Label id; @FXML - private Label phone; - @FXML - private Label address; - @FXML - private Label email; + private Label credits; @FXML private FlowPane tags; + @FXML + private Label title; /** - * Creates a {@code PersonCode} with the given {@code Person} and index to display. + * Creates a {@code ModuleCode} with the given {@code Module} and index to display. */ - public PersonCard(Person person, int displayedIndex) { + public ModuleCard(Module module, int displayedIndex) { super(FXML); - this.person = person; + this.module = module; id.setText(displayedIndex + ". "); - name.setText(person.getName().fullName); - phone.setText(person.getPhone().value); - address.setText(person.getAddress().value); - email.setText(person.getEmail().value); - person.getTags().stream() + code.setText(module.getModuleCode().toString()); + title.setText(module.getModuleTitle().toString()); + credits.setText(module.getModularCredits().value + " MCs"); + module.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); } @@ -65,13 +62,13 @@ public boolean equals(Object other) { } // instanceof handles nulls - if (!(other instanceof PersonCard)) { + if (!(other instanceof ModuleCard)) { return false; } // state check - PersonCard card = (PersonCard) other; + ModuleCard card = (ModuleCard) other; return id.getText().equals(card.id.getText()) - && person.equals(card.person); + && module.equals(card.module); } } diff --git a/src/main/java/seedu/address/ui/ModuleListPanel.java b/src/main/java/seedu/address/ui/ModuleListPanel.java new file mode 100644 index 00000000000..001b93696f7 --- /dev/null +++ b/src/main/java/seedu/address/ui/ModuleListPanel.java @@ -0,0 +1,49 @@ +package seedu.address.ui; + +import java.util.logging.Logger; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.layout.Region; +import seedu.address.commons.core.LogsCenter; +import seedu.address.model.module.Module; + +/** + * Panel containing the list of modules. + */ +public class ModuleListPanel extends UiPart { + private static final String FXML = "ModuleListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(ModuleListPanel.class); + + @FXML + private ListView moduleListView; + + /** + * Creates a {@code ModuleListPanel} with the given {@code ObservableList}. + */ + public ModuleListPanel(ObservableList moduleList) { + super(FXML); + moduleListView.setItems(moduleList); + moduleListView.setCellFactory(listView -> new ModuleListViewCell()); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Module} using a {@code ModuleCard}. + */ + class ModuleListViewCell extends ListCell { + @Override + protected void updateItem(Module module, boolean empty) { + super.updateItem(module, empty); + + if (empty || module == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new ModuleCard(module, getIndex() + 1).getRoot()); + } + } + } + +} diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java deleted file mode 100644 index f4c501a897b..00000000000 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ /dev/null @@ -1,49 +0,0 @@ -package seedu.address.ui; - -import java.util.logging.Logger; - -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.layout.Region; -import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; - -/** - * Panel containing the list of persons. - */ -public class PersonListPanel extends UiPart { - private static final String FXML = "PersonListPanel.fxml"; - private final Logger logger = LogsCenter.getLogger(PersonListPanel.class); - - @FXML - private ListView personListView; - - /** - * Creates a {@code PersonListPanel} with the given {@code ObservableList}. - */ - public PersonListPanel(ObservableList personList) { - super(FXML); - personListView.setItems(personList); - personListView.setCellFactory(listView -> new PersonListViewCell()); - } - - /** - * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. - */ - class PersonListViewCell extends ListCell { - @Override - protected void updateItem(Person person, boolean empty) { - super.updateItem(person, empty); - - if (empty || person == null) { - setGraphic(null); - setText(null); - } else { - setGraphic(new PersonCard(person, getIndex() + 1).getRoot()); - } - } - } - -} diff --git a/src/main/java/seedu/address/ui/ResultDisplay.java b/src/main/java/seedu/address/ui/ResultDisplay.java index 7d98e84eedf..9aef27f65fa 100644 --- a/src/main/java/seedu/address/ui/ResultDisplay.java +++ b/src/main/java/seedu/address/ui/ResultDisplay.java @@ -7,7 +7,7 @@ import javafx.scene.layout.Region; /** - * A ui for the status bar that is displayed at the header of the application. + * A ui for displaying feedbacks to user commands. */ public class ResultDisplay extends UiPart { @@ -20,9 +20,27 @@ public ResultDisplay() { super(FXML); } + /** + * Displays the specified feedback to the user via the result display. + * + */ public void setFeedbackToUser(String feedbackToUser) { requireNonNull(feedbackToUser); resultDisplay.setText(feedbackToUser); } + /** + * Hides the result display. + */ + public void hide() { + getRoot().setVisible(false); + } + + /** + * Shows the result display. + */ + public void show() { + getRoot().setVisible(true); + } + } diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java index 882027e4537..40836773e94 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/seedu/address/ui/UiManager.java @@ -20,7 +20,7 @@ public class UiManager implements Ui { public static final String ALERT_DIALOG_PANE_FIELD_ID = "alertDialogPane"; private static final Logger logger = LogsCenter.getLogger(UiManager.class); - private static final String ICON_APPLICATION = "/images/address_book_32.png"; + private static final String ICON_APPLICATION = "/images/gradpad.png"; private Logic logic; private MainWindow mainWindow; diff --git a/src/main/resources/data/GEM/GEHsem1.json b/src/main/resources/data/GEM/GEHsem1.json new file mode 100644 index 00000000000..88cedd1ce6b --- /dev/null +++ b/src/main/resources/data/GEM/GEHsem1.json @@ -0,0 +1,83 @@ +{ + "modules" : [ { + "tagged" : [ "GEH" ], + "code" : "GEH1002", + "title" : "Economic Issues in the Developing World", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1004", + "title" : "Chinese Heritage: Chinese History and Literature", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1009", + "title" : "Framing Bollywood: Unpacking The Magic", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1013", + "title" : "Pirates, Oceans and the Maritime World", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1014", + "title" : "Samurai, Geisha, Yakuza as Self or Other", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1025", + "title" : "Global Environmental Issues", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1032", + "title" : "Modern Technology in Medicine and Healthcare", + "credits" : "4" + }, { + "tagged" : [ "GEH"], + "code" : "GEH1036", + "title" : "Living with Mathematics", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1043", + "title" : "Microbes Which Changed Human History", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1049", + "title" : "Public Health In Action", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1061", + "title" : "Representation and Media", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1062", + "title" : "Ghosts and Spirits in Society and Culture", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1069", + "title" : "Art in Asia: Through Media, Style, Space and Time", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1070", + "title" : "Traditional Chinese Knowledge of Health and Well-being", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1073", + "title" : "THE ART OF CHINESE POETRY: PAST AND PRESENT", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1079", + "title" : "Life, Disrupted: The Sharing Revolution", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GEHsem2.json b/src/main/resources/data/GEM/GEHsem2.json new file mode 100644 index 00000000000..ad34f24b1e9 --- /dev/null +++ b/src/main/resources/data/GEM/GEHsem2.json @@ -0,0 +1,23 @@ +{ + "modules" : [ { + "tagged" : [ "GEH" ], + "code" : "GEH1005", + "title" : "Crime Fiction in English and Chinese", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1006", + "title" : "Chinese Music, Language And Literature (In English)", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1049", + "title" : "Public Health In Action", + "credits" : "4" + }, { + "tagged" : [ "GEH" ], + "code" : "GEH1074", + "title" : "Luck", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GEQ.json b/src/main/resources/data/GEM/GEQ.json new file mode 100644 index 00000000000..2cd9bfc31ae --- /dev/null +++ b/src/main/resources/data/GEM/GEQ.json @@ -0,0 +1,13 @@ +{ + "modules" : [{ + "tagged" : [ "GEQ" ], + "code" : "GEQ1000", + "title" : "Asking Questions", + "credits" : "4" + }, { + "tagged" : [ "GEQ" ], + "code" : "GEQ1917", + "title" : "Understanding and Critiquing Sustainability\n(offered exclusively for Year One RVRC residents)", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GER.json b/src/main/resources/data/GEM/GER.json new file mode 100644 index 00000000000..fe2e46ef828 --- /dev/null +++ b/src/main/resources/data/GEM/GER.json @@ -0,0 +1,8 @@ +{ + "modules" : [ { + "tagged" : [ "GER" ], + "code" : "GER1000", + "title" : "Quantitative Reasoning", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GESsem1.json b/src/main/resources/data/GEM/GESsem1.json new file mode 100644 index 00000000000..c2b543ce78f --- /dev/null +++ b/src/main/resources/data/GEM/GESsem1.json @@ -0,0 +1,68 @@ +{ + "modules" : [ { + "tagged" : [ "GES" ], + "code" : "GES1002", + "title" : "Global Economic Dimensions of Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1003", + "title" : "Changing Landscapes of Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1005", + "title" : "Everyday Life of Chinese Singaporean: Past & Present", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1007", + "title" : "South Asia In Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1008", + "title" : "Ethnicity and Nation-Building", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1011", + "title" : "The Evolution of a Global City-State", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1012", + "title" : "Popular Culture in Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1021", + "title" : "Natural Heritage Of Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1024", + "title" : "Real Estate Development & Investment Law", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1026", + "title" : "Urban Planning In Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1031", + "title" : "Culture & Communication In Singapore", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1033", + "title" : "Who Moved My OB Markers?", + "credits" : "4" + }, { + "tagged" : [ "GES" ], + "code" : "GES1035", + "title" : "Singapore: Imagining the Next 50 years", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GESsem2.json b/src/main/resources/data/GEM/GESsem2.json new file mode 100644 index 00000000000..8c92986292c --- /dev/null +++ b/src/main/resources/data/GEM/GESsem2.json @@ -0,0 +1,8 @@ +{ + "modules" : [ { + "tagged" : [ "GES" ], + "code" : "GES1005", + "title" : "Everyday Life of Chinese Singaporean: Past & Present", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GETsem1.json b/src/main/resources/data/GEM/GETsem1.json new file mode 100644 index 00000000000..b2846e31570 --- /dev/null +++ b/src/main/resources/data/GEM/GETsem1.json @@ -0,0 +1,48 @@ +{ + "modules" : [ { + "tagged" : [ "GET" ], + "code" : "GET1002", + "title" : "Bridging East And West: Exploring Chinese Communication", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1020", + "title" : "Darwin and evolution", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1023", + "title" : "Thinking Like An Economist", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1031", + "title" : "Computational Thinking", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1034", + "title" : "Communication and Critical Thinking for Community Leadership", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1035", + "title" : "Critical Perspectives In Advertising", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1037", + "title" : "Big Picture History", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1043", + "title" : "Universe, Big Bang, and Unsolved Mysteries", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1048", + "title" : "Science: From Thinking to Narratives", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/GEM/GETsem2.json b/src/main/resources/data/GEM/GETsem2.json new file mode 100644 index 00000000000..9734249e96f --- /dev/null +++ b/src/main/resources/data/GEM/GETsem2.json @@ -0,0 +1,13 @@ +{ + "modules" : [ { + "tagged" : [ "GET" ], + "code" : "GET1046", + "title" : "I do not think therefore I am", + "credits" : "4" + }, { + "tagged" : [ "GET" ], + "code" : "GET1048", + "title" : "Science: From Thinking to Narratives", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/ITProfessionalism.json b/src/main/resources/data/ITProfessionalism.json new file mode 100644 index 00000000000..8b4f2320b64 --- /dev/null +++ b/src/main/resources/data/ITProfessionalism.json @@ -0,0 +1,18 @@ +{ + "modules" : [ { + "tagged" : [ "ITProfessionalism" ], + "code" : "IS1103", + "title" : "Ethics in Computing", + "credits" : "4" + }, { + "tagged" : [ "ITProfessionalism" ], + "code" : "CS2101", + "title" : "Effective Communication for Computing Professionals", + "credits" : "4" + }, { + "tagged" : [ "ITProfessionalism" ], + "code" : "ES2660", + "title" : "Communicating in the Information Age", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/foundationmodules.json b/src/main/resources/data/foundationmodules.json new file mode 100644 index 00000000000..7c9643d9b63 --- /dev/null +++ b/src/main/resources/data/foundationmodules.json @@ -0,0 +1,43 @@ +{ + "modules" : [ { + "tagged" : [ "Foundation" ], + "code" : "CS1101S", + "title" : "Programming Methodology", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS1231S", + "title" : "Discrete Structures", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS2030S", + "title" : "Programming Methodology II", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS2040S", + "title" : "Data Structures and Algorithms", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS2100", + "title" : "Computer Organisation", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS2103T", + "title" : "Software Engineering", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS2106", + "title" : "Introduction to Operating Systems", + "credits" : "4" + }, { + "tagged" : [ "Foundation" ], + "code" : "CS3230", + "title" : "Design and Analysis of Algorithms", + "credits" : "4" + }] +} diff --git a/src/main/resources/data/industrialexperience.json b/src/main/resources/data/industrialexperience.json new file mode 100644 index 00000000000..ad3c8313cdd --- /dev/null +++ b/src/main/resources/data/industrialexperience.json @@ -0,0 +1,43 @@ +{ + "modules" : [{ + "tagged" : [ "Internship" ], + "code" : "CP3880", + "title" : "Advanced Technology Attachment Programme", + "credits" : "12" + }, { + "tagged" : [ "Internship" ], + "code" : "CP3200", + "title" : "Internship", + "credits" : "6" + }, { + "tagged" : [ "Internship" ], + "code" : "CP3202", + "title" : "Internship II", + "credits" : "6" + }, { + "tagged" : [ "Internship" ], + "code" : "CP3107", + "title" : "Computing for Voluntary Welfare Organisations", + "credits" : "6" + }, { + "tagged" : [ "Internship" ], + "code" : "CP3110", + "title" : "Computing for Voluntary Welfare Organisations II", + "credits" : "6" + }, { + "tagged" : [ "Internship" ], + "code" : "IS4010", + "title" : "Industry Internship Programme", + "credits" : "12" + }, { + "tagged" : [ "Internship" ], + "code" : "TR3202", + "title" : "Startup Internship Programme", + "credits" : "12" + }, { + "tagged" : [ "Internship" ], + "code" : "CP4101", + "title" : "BComp Dissertation", + "credits" : "12" + }] +} diff --git a/src/main/resources/data/mathmodules.json b/src/main/resources/data/mathmodules.json new file mode 100644 index 00000000000..293003faf78 --- /dev/null +++ b/src/main/resources/data/mathmodules.json @@ -0,0 +1,18 @@ +{ + "modules" : [ { + "tagged" : [ "MathAndSciences" ], + "code" : "MA1521", + "title" : "Calculus for Computing", + "credits" : "4" + }, { + "tagged" : [ "MathAndSciences" ], + "code" : "MA1101R", + "title" : "Linear Algebra I", + "credits" : "4" + }, { + "tagged" : [ "MathAndSciences" ], + "code" : "ST2334", + "title" : "Probability and Statistics", + "credits" : "4" + } ] +} diff --git a/src/main/resources/data/modules.json b/src/main/resources/data/modules.json new file mode 100644 index 00000000000..247d4804c0c --- /dev/null +++ b/src/main/resources/data/modules.json @@ -0,0 +1,1667 @@ +{ + "CP3107" : { + "moduleCode" : "CP3107", + "title" : "Computing for Voluntary Welfare Organisations", + "moduleCredit" : "6", + "semesters" : [ 1 ], + "description" : "This is a project-based module that provides students with\ntraining in software engineering by working on an actual\nsoftware system that supports a local voluntary welfare\norganisation. This module is graded on a Completed\nSatisfactorily/Completed Unsatisfactorily (CS/CU) basis.", + "preclusion" : null, + "prerequisite" : "CS2010 or CS2020 or (((CS2030 or its equivalent) or CS2113/T) and CS2040/C). Student selection process will be enforced." + }, + "LSM1306" : { + "moduleCode" : "LSM1306", + "title" : "Forensic Science", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Crime is one feature of human behaviour that fascinates our community. How crimes impact our society and how crimes are investigated and solved in the Singapore context is the focus of the module. The module is designed to enable students to appreciate why and how crimes are committed, to understand how crimes are solved in Singapore using investigative, and the latest scientific and forensic techniques, and to learn the role of the major stakeholders in the Criminal Justice System. Experts from law, pharmacy, statistics, the Health Sciences Authority and the Singapore Police Force will cover topics related to forensic science.", + "preclusion" : "GEK1542", + "prerequisite" : null + }, + "CP3106" : { + "moduleCode" : "CP3106", + "title" : "Independent Project", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "", + "preclusion" : null, + "prerequisite" : "[(CS2102 or CS2102S) and CS2105 and read (CS3214 or CS3215)] or IS3102 or IS4102 or CS3201 or CS3281 or CS4201 or CS4203" + }, + "LSM1301" : { + "moduleCode" : "LSM1301", + "title" : "General Biology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This is an introductory module that explores what a living thing is, the basics of life, and the science behind it. The course will introduce the chemistry of life and the unit of life. The question of how traits are inherited will be discussed and the field of biotechnology, including its applications and the ethical issues involved be will introduced. The diversity of life on earth will be explored, with discussions how life on earth possibly came about and how biologists try to classify and make sense of the diversity. The course will also introduce the concept of life functions from cells to tissues and from organs to systems. The concept of how organisms maintain their internal constancy and organisation of major organ systems will be discussed. The focus will be to introduce the unifying concepts in biology and how they play a role in everyday life.", + "preclusion" : "GCE `A’ Level or H2 Biology or equivalent, or LSM1301X", + "prerequisite" : null + }, + "CS2106" : { + "moduleCode" : "CS2106", + "title" : "Introduction to Operating Systems", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the basic concepts in operating systems and links it with contemporary operating systems (eg. Unix/Linux and Windows). It focuses on OS structuring and architecture, processes, memory management, concurrency and file systems. Topics include kernel architecture, system calls, interrupts, models of processes, process abstraction and services, scheduling, review of physical memory and memory management hardware, kernel memory management, virtual memory and paging, caches, working set, deadlock, mutual exclusion, synchronisation mechanisms, data and metadata in file systems, directories and structure, file system abstraction and operations, OS protection mechanisms, and user authentication.", + "preclusion" : "CG2271 or EE4214. CEG students are not allowed to take this module.", + "prerequisite" : "CS2100 or EE2007 or EE2024 or EE2028" + }, + "CS2105" : { + "moduleCode" : "CS2105", + "title" : "Introduction to Computer Networks", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module aims to provide a broad introduction to computer networks and network application programming. It covers the main concepts, the fundamental principles, and the high-level workings of important protocols in each of the Internet protocol layer. Topics include the Web and Web applications, DNS services, socket programming, reliable protocols, transport and network layer protocols, secure communication, LAN, and data communication. Practical assignments and handson exercises expose students to network application programming and various networking tools and utilities.", + "preclusion" : "IT2001, EE3204/E, EE4204/E, EE4210/E. CEG, CPE and EEE students are not allowed to take this module.", + "prerequisite" : "(CS1020 or its equivalent) or CS2020 or (CS2040 or its equivalents)" + }, + "CS2108" : { + "moduleCode" : "CS2108", + "title" : "Introduction to Media Computing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces students to (i) the fundamental principles, theory, algorithms, and data structures behind digital representation, compression, synchronization, and processing of image, audio, and video data types, and (ii) challenges and issues in developing media-rich applications, such as media streaming and media retrieval. Students will be exposed to the workings of common media file format and common manipulation techniques on media data. After taking the module, students should be confident enough in developing media applications and make appropriate trade-off and design decisions when dealing in media data in their software.", + "preclusion" : "CS3246", + "prerequisite" : "(CS1020 or its equivalent) or CS2020 or (CS2040 or its equivalent)" + }, + "CS2107" : { + "moduleCode" : "CS2107", + "title" : "Introduction to Information Security", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module serves as an introductory module on information security. It illustrates the fundamentals of how systems fail due to malicious activities and how they can be protected. The module also places emphasis on the practices of secure programming and implementation. Topics covered include classical/historical ciphers, introduction to modern ciphers and cryptosystems, ethical, legal and organisational aspects, classic examples of direct attacks on computer systems such as input validation vulnerability, examples of other forms of attack such as social engineering/phishing attacks, and the practice of secure programming.", + "preclusion" : null, + "prerequisite" : "CS1010 or its equivalence" + }, + "CS3245R" : { + "moduleCode" : "CS3245R", + "title" : "Information Retrieval", + "moduleCredit" : "1", + "semesters" : [ 1 ], + "description" : "This 1-MC module adds a research component to the host module, enabling students to acquire more in-depth understanding of the research issues pertaining to the subject matter.", + "preclusion" : null, + "prerequisite" : "Co-read with host module in current semester or pass host module in previous semester. Student selection process is enforced." + }, + "CS5218" : { + "moduleCode" : "CS5218", + "title" : "Principles and Practice of Program Analysis", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "Program analysis denotes automated processes for predicting, estimating or proving properties of program behavior, whether functional or non-functional. Example uses are compiler optimization, bug detection, performance evaluation, detection of security vulnerabilities, amongst many others. This module first provides the rigorous mathematical foundations. This step is necessary in order to understand the common elements within the broad area of software analysis. Secondly, through the use of a state-of-the-art program analysis system, this module provides hands-on instruction on programming real-life analyses. In the end, the graduating student will be able to address a broad spectrum of program analysis in a practical way.", + "preclusion" : null, + "prerequisite" : "CS4212 Compiler Design or CS4215 Programming Language Implementation" + }, + "CS5339" : { + "moduleCode" : "CS5339", + "title" : "Theory and Algorithms for Machine Learning", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The module aims to provide a broad theoretical understanding of machine learning and how the theory guides the development of algorithms and applications. Topics covered include the approximation capabilities of common function classes used for machine learning, such as decision trees, neural networks, and support vector machines, the sample complexity of learning different function classes and methods of reducing the estimation error such as regularization and model selection, and computational methods used for learning such as convex optimization, greedy methods, and stochastic gradient\ndescent.", + "preclusion" : "MA4270", + "prerequisite" : "CS3244" + }, + "CS2102" : { + "moduleCode" : "CS2102", + "title" : "Database Systems", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The aim of this module is to introduce the fundamental concepts and techniques necessary for the understanding and practice of design and implementation of database applications and of the management of data with relational database management systems. The module covers practical and theoretical aspects of design with entity-relationship model, theory of functional dependencies and normalisation by decomposition in second, third and Boyce-Codd normal forms. The module covers practical and theoretical aspects of programming with SQL data definition and manipulation sublanguages, relational tuple calculus, relational domain calculus and relational algebra.", + "preclusion" : "CS2102S, IT2002", + "prerequisite" : "((CS1020 or its equivalent) or CS2020 or (CS2030 or its equivalent) or (CS2040 or its equivalent)) \nand (MA1100 or (CS1231 or its equivalent))" + }, + "CS4248" : { + "moduleCode" : "CS4248", + "title" : "Natural Language Processing", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module deals with computer processing of human languages, emphasizing a corpus-based empirical approach. The topics covered include: 1. Linguistic essentials. 2. Basic techniques and algorithms: Hidden Markov model, Viterbi algorithm, supervised learning algorithms. 3. Words: part-of-speech tagging. 4. Syntax: noun phrase chunking, named entity tagging, parsing (top down, bottom up, probabilistic). 5. Semantics: word sense disambiguation. 6. Pragmatics: discourse, co-reference resolution. 7. Applications: text categorisation, text summarisation, language identification, information extraction, question answering, machine translation.", + "preclusion" : null, + "prerequisite" : "(CS3243 or CS3245) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS2101" : { + "moduleCode" : "CS2101", + "title" : "Effective Communication for Computing Professionals", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module aims to equip students with the skills needed to communicate technical information to technical and nontechnical audiences, and to create comprehensible software documentation. A student-centric approach will\nbe adopted to encourage independent and collaborative learning while engaging students in team-based projects. Students will learn interpersonal and intercultural\ncommunication skills as well as hone their oral and written communication skills. Assessment modes include a variety of oral and written communication tasks such as reports, software guides, oral presentations, software demonstrations and project blogs.", + "preclusion" : "CS2103 Software Engineering, IS2101 Business Technical Communication or its equivalent, ES2002, ES2007D, and ES1601.", + "prerequisite" : "Students have to complete ES1000 and/or ES1103 (if required to take the module/s) before reading this module." + }, + "CS4249" : { + "moduleCode" : "CS4249", + "title" : "Phenomena and Theories of Human-Computer Interaction", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module teaches the underlying science of Human-Computer Interaction (HCI) and its application to user interface design. It surveys a wide range of psychological theories beginning with organizational behaviour approaches, understanding of work and workflow within organizations, and moving on to understanding human psychological architecture and processing constraints. It demonstrates via a combination of scientific theory understanding and engineering modelling the solutions of design problems facing a user interface designer. It also covers new design methods and techniques available and the new conceptual mechanisms used in HCI such as the metaphors for describing user interaction.", + "preclusion" : null, + "prerequisite" : "CS3240 or NM2213 or NM2216" + }, + "CS2104" : { + "moduleCode" : "CS2104", + "title" : "Programming Language Concepts", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module introduces the concepts that serve as a basis for hundreds of programming languages. It aims to provide the students with a basic understanding and appreciation of the various essential programming-languages constructs, programming paradigms, evaluation criteria and language implementation issues. The module covers concepts from imperative, object-oriented, functional, logic, constraints, and concurrent programming. These concepts are illustrated by examples from varieties of languages such as Pascal, C, Java, Smalltalk, Scheme, Haskell, Prolog. The module also introduces various implementation issues, such as pseudo-code interpretation, static and dynamic semantics, abstract machine, type inferencing, etc.", + "preclusion" : null, + "prerequisite" : "(CS1020 or its equivalent) or CS2020 or (CS2030 or its equivalent) or CS2113/T" + }, + "CS4246" : { + "moduleCode" : "CS4246", + "title" : "AI Planning and Decision Making", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the major concepts and paradigms in planning and decision making in complex environments. It examines issues, challenges, and techniques in problem representation, goal or objective specification, response selection, and action\nconsequence for a wide range of strategic and tactical planning and decision making situations. Topics covered include deterministic and non-deterministic planning,\npractical planning and acting under resource constraints and uncertainy, expected utility and rational decision making, decision networks, Markov decision processes,\nelementary game theory, and multi-agent planning and decision making.", + "preclusion" : "CS5446", + "prerequisite" : "CS3243 and \n(EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS2103" : { + "moduleCode" : "CS2103", + "title" : "Software Engineering", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the necessary conceptual and analytical tools for systematic and rigorous development of software systems. It covers four main areas of software development, namely object-oriented system analysis, object-oriented system modelling and design, implementation, and testing, with emphasis on system modelling and design and implementation of software modules that work cooperatively to fulfill the requirements of the system. Tools and techniques for software development, such as Unified Modelling Language (UML), program specification, and testing methods, will be taught. Major software engineering issues such as modularisation criteria, program correctness, and software quality will also be covered.", + "preclusion" : "CS2103T, CS2113, CS2113T", + "prerequisite" : "(CS1020 or its equivalent) or CS2020 or ((CS2030 or its equivalent) and (CS2040 or its equivalent))" + }, + "CS4247" : { + "moduleCode" : "CS4247", + "title" : "Graphics Rendering Techniques", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module provides a general treatment of real-time and offline rendering techniques in 3D computer graphics. Specific topics include the raster graphics pipeline, viewing and transformation, real-time mapping techniques, real-time shadow algorithms, local reflection models, global illumination, distributed ray tracing, photon mapping, radiosity, volume rendering, image-based rendering and modelling, and strategies for anti-aliasing and photo-realism.", + "preclusion" : null, + "prerequisite" : "CS3241" + }, + "CS4244" : { + "moduleCode" : "CS4244", + "title" : "Knowledge Representation and Reasoning", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This course will focus on core issues of representation and reasoning of the knowledge in the context of design of intelligent machines. We will focus on how logic can be used to formalise and perform deduction from existing knowledge. We will then discuss compilation techniques. Finally, we will discuss limitations of monotonic logic and discuss challenges for non-monotonic reasoning.", + "preclusion" : null, + "prerequisite" : "CS3243" + }, + "CS2100" : { + "moduleCode" : "CS2100", + "title" : "Computer Organisation", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The objective of this module is to familiarise students with the fundamentals of computing devices. Through this module students will understand the basics of data representation, and how the various parts of a computer work, separately and with each other. This allows students to understand the issues in computing devices, and how these issues affect the implementation of solutions. Topics covered include data representation systems, combinational and sequential circuit design techniques, assembly language, processor execution cycles, pipelining, memory hierarchy and input/output systems.", + "preclusion" : "CS1104 or Students from Department of ECE", + "prerequisite" : "CS1010 or its equivalent" + }, + "CS4242" : { + "moduleCode" : "CS4242", + "title" : "Social Media Computing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The emergence of WWW, smart mobile devices and social networks has revolutionised the way we communicate, create, disseminate, and consume information. This has ushered in a new era of communications that involves complex information exchanges and user relationships. This module aims to provide students with a good understanding of the social network phenomena and computational skills for analysing the complex social relation networks between users, the contents they shared, and the ways contents and events are perceived and propagated through the social networks. The analysis will provide better understanding of the concerns and interests of users, and uncover live and emerging events that will affect the community.", + "preclusion" : null, + "prerequisite" : "CS2108 Introduction to Media Computing and CS3245 Information Retrieval." + }, + "CS5332" : { + "moduleCode" : "CS5332", + "title" : "Biometric Authentication", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "Biometrics (such as fingerprint, iris images) are commonly used for authentication. This module covers authentication methods, different types of biometrics, pattern recognition, performance measurement, spoofing attacks, as well as issues such as privacy, user acceptance, and standards compliance. Students will gain a solid understanding of the fundamentals of the technology underlying biometric authentication, and the key issues to be addressed for successful deployment. Both the theoretical and practical\naspects of biometrics authentication will be discussed.", + "preclusion" : null, + "prerequisite" : "(CS2040 or its equivalent) and (MA1101R or MA1311 or MA1508E or MA1513) and \n(MA1102R or MA1505 or MA1507 or (MA1511 and MA1512) or MA1521) and \n(EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS1010" : { + "moduleCode" : "CS1010", + "title" : "Programming Methodology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the fundamental concepts of problem solving by computing and programming using an imperative programming language. It is the first and foremost introductory course to computing. Topics covered include computational thinking and computational problem solving, designing and specifying an algorithm, basic problem formulation and problem solving approaches, program development, coding, testing and debugging, fundamental programming constructs (variables, types, expressions, assignments, functions, control structures, etc.), fundamental data structures (arrays, strings, composite data types), basic sorting, and recursion.", + "preclusion" : "CS1010E, CS1010J, CS1010S, CS1010X, CS1010XCP, CS1101S", + "prerequisite" : null + }, + "CS2220" : { + "moduleCode" : "CS2220", + "title" : "Introduction to Computational Biology", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This course aims to develop flexible and logical problem solving skills, understanding of main bioinformatics problems, and appreciation of main techniques and approaches to bioinformatics. Through case studies and hands-on exercises, the student will (i) master the basic tools and approaches for analysis of DNA sequences, protein sequences, gene expression profiles, etc. (ii) understand important problems and applications of computational biology, including identifying functional features in DNA and protein sequences, predicting protein function, and deriving diagnostic models from gene expression profiles, (iii) be confident to propose new solutions to both existing and emerging problems in computational biology.", + "preclusion" : null, + "prerequisite" : "(CS1020 or its equivalent) or CS2020 or (CS2040 or its equivalent)" + }, + "CS4243" : { + "moduleCode" : "CS4243", + "title" : "Computer Vision and Pattern Recognition", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module is for undergraduates who are interested in computer vision and its applications. It covers (a) the basic skills needed in handling images and videos, (b) the basic theories needed to understand geometrical computer vision, and (c) pattern recognition. Topics covered in image handling include: contrast stretch, histogram equalization, noise removal, and color space. Topics covered in geometrical vision include: affine transform, vanishing points, camera projection models, homography, camera calibration, rotation representations including quaternions, epipolar geometry, binocular stereo, structure from motion. Topics covered for pattern recognition include principal component analysis.", + "preclusion" : "EE4212 Computer Vision\nEE4704 (Image Processing and Analysis)", + "prerequisite" : "((CS1020 or its equivalent) or (((CS2030 or its equivalent) or CS2113/T) and (CS2040 or its equivalent))) and \n(MA1101R or MA1311 or MA1508E or MA1513) and \n(MA1102R or MA1505 or MA1507 or (MA1511 and MA1512) or MA1521) and \n(EE2012/A or MA2216 or ST1131/A or ST1232 or ST2131 or ST2334)" + }, + "CS5331" : { + "moduleCode" : "CS5331", + "title" : "Web Security", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to prepare graduate students for understanding the security of the latest web platform and its interplay with operating systems and the cloud infrastructure. The topics covered include the design of web browsers and web \napplications, vulnerabilities in web applications and web browsers, design of web scanners, authentication in web-based platforms, security policies and enforcement mechanisms. This module also covers security topics on the interface between the \nweb platform and the backend systems, such as the underlying database systems and cloud infrastructure.", + "preclusion" : null, + "prerequisite" : "CS3235 Computer Security" + }, + "CS4240" : { + "moduleCode" : "CS4240", + "title" : "Interaction Design for Virtual and Augmented Reality", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to expose students to the human-centered principles of designing and building virtual reality (VR) and augmented reality (AR) applications. Students will learn about the fundamentals of VR and AR, human perceptions of reality, and the design patterns and guidelines for user interactions within VR/AR applications. Students will gain hands on experience building VR/AR applications applying these interaction principles.", + "preclusion" : null, + "prerequisite" : "CS3240 and (MA1301 or A-level / H2 Mathematics)" + }, + "CS5330" : { + "moduleCode" : "CS5330", + "title" : "Randomized Algorithms", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The module will cover basic concepts in the design and analysis of randomized algorithms. It will cover both basic techniques, such as Chernoff bounds, random walks, and the probabilistic method, and a variety of practical algorithmic applications, such as load balancing, hash functions, and graph/network algorithms. The focus will be on utilizing randomization to develop algorithms that are more efficient and/or simpler than their deterministic counterparts.", + "preclusion" : null, + "prerequisite" : "CS3230" + }, + "CS2103T" : { + "moduleCode" : "CS2103T", + "title" : "Software Engineering", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the necessary conceptual and analytical tools for systematic and rigorous development of software systems. It covers four main areas of software development, namely object-oriented system analysis, object-oriented system modelling and design, implementation, and testing, with emphasis on system modelling and design and implementation of software modules that work cooperatively to fulfill the requirements of the system. Tools and techniques for software development, such as Unified Modelling Language (UML), program specification, and testing methods, will be taught. Major software engineering issues such as modularisation criteria, program correctness, and software quality will also be covered.", + "preclusion" : "CS2103, CS2113, CS2113T, IS2101 or its equivalent.", + "prerequisite" : "For SoC students only. (CS1020 or its equivalent) or CS2020 or ((CS2030 or its equivalent) and (CS2040 or its equivalent))" + }, + "ST2334" : { + "moduleCode" : "ST2334", + "title" : "Probability and Statistics", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "Basic concepts of probability, conditional probability, independence, random variables, joint and marginal distributions, mean and variance, some common probability distributions, sampling distributions, estimation and hypothesis testing based on a normal population. This module is targeted at students who are interested in Statistics and are able to meet the pre-requisites. Preclude ME students taking or have taken ME4273.", + "preclusion" : "ST1131, ST1131A, ST1232, ST2131, MA2216, CE2407, EC2231, EC2303, PR2103, DSC2008. ME students taking or having taken ME4273. All ISE students.", + "prerequisite" : "MA1102R or MA1312 or MA1505 or MA1507 or MA1521" + }, + "CS1231S" : { + "moduleCode" : "CS1231S", + "title" : "Discrete Structures", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces mathematical tools required in the study of computer science. Topics include: (1) Logic and proof techniques: propositions, conditionals, quantifications. (2) Relations and Functions: Equivalence relations and partitions. Partially ordered sets. Well-Ordering Principle. Function equality. Boolean/identity/inverse functions. Bijection. (3) Mathematical formulation of data models (linear model, trees, graphs). (4) Counting and Combinatoric: Pigeonhole Principle. Inclusion-Exclusion Principle. Number of relations on a set, number of injections from one finite set to another, Diagonalization proof: An infinite countable set has an uncountable power set; Algorithmic proof: An infinite set has a countably infinite subset. Subsets of countable sets are countable.", + "preclusion" : "MA1100 and CS1231 or its equivalent", + "prerequisite" : "A-level Mathematics or H2 Mathematics or MA1301 or MA1301FC or MA1301X" + }, + "CS4239" : { + "moduleCode" : "CS4239", + "title" : "Software Security", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Software engineering processes need to include security considerations in the modern world. This module familiarizes students to security issues in different stages of the software life-cycle. At the end of the module, the students are expected to understand secure programming practices, be able to analyse and check for impact of malicious inputs in programs, and employ specific testing techniques which can help detect software vulnerabilities.", + "preclusion" : "CS5439", + "prerequisite" : "CS3235 Computer Security and (CS2103 or its equivalent)" + }, + "CS4238" : { + "moduleCode" : "CS4238", + "title" : "Computer Security Practice", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This is a practice security module with emphasis on hands-on experiences of computer security. The objective of this module is to connect computer security knowledge to practical skills, including common attacks and protection mechanisms, system administration, and development of secured software. Topics covered include network security, operating system security, and application security, such as DNS attacks, memory-error exploits, and web application attacks. Students will learn through lab-based exercises and assignments.", + "preclusion" : null, + "prerequisite" : "CS3235 Computer Security" + }, + "CS5446" : { + "moduleCode" : "CS5446", + "title" : "AI Planning and Decision Making", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the major concepts and paradigms in planning and decision making in complex environments. It examines issues, challenges, and techniques in problem representation, goal or objective specification, response selection, and action consequence for a wide range of strategic and tactical planning and decision making situations. Topics covered include deterministic and nondeterministic planning, practical planning and acting under resource constraints and uncertainty, expected utility and rational decision making, decision networks, Markov decision processes, elementary game theory, and multiagent planning and decision making.", + "preclusion" : "CS4246", + "prerequisite" : "CS3243 and \n(EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS4236" : { + "moduleCode" : "CS4236", + "title" : "Cryptography Theory and Practice", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module aims to introduce the foundation, principles and concepts behind cryptology and the design of secure communication systems. The emphasis is on the formulation and techniques of various cryptographic primitives, and on the secure usage of such primitives to achieve the goals of confidentially, integrity, and authenticity in both theoretical settings and practical scenarios. Basic topics include pseudorandom functions, symmetric key encryption, public key encryption, message\nauthentication codes, hash functions, digital signatures, key exchange and PKI. Selected topics may include: secret sharing, TCP/IP security, Kerberos, SSL, trusted computing, side-channel attacks.", + "preclusion" : null, + "prerequisite" : "((CS2010 or its equivalent) or CS2020 or (CS2040 or its equivalent)) and (MA1100 or (CS1231 or its equivalent)) and CS2107" + }, + "CS4234" : { + "moduleCode" : "CS4234", + "title" : "Optimisation Algorithms", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module covers common algorithmic techniques for solving optimisation problems, and introduces students to approaches for finding good-enough solutions to NP-hard problems. Topics covered include linear and integer programming, network flow algorithms, local search heuristics, approximation algorithms, and randomized algorithms. Through analysis and application of the techniques to a variety of canonical problems, students develop confidence to (i) appropriately model a given optimisation problem, (ii) apply appropriate algorithmic techniques to solve the problem, (iii) analyse the properties of the problem and candidate algorithms, such as time and space complexity, convergence, approximability, and optimality bound.", + "preclusion" : null, + "prerequisite" : "CS3230 and \n(MA1101R or MA1311 or MA1508E or MA1513)" + }, + "CS5322" : { + "moduleCode" : "CS5322", + "title" : "Database Security", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Database security has a great impact on the design of today's information systems. This course will provide an overview of database security concepts and techniques and discuss new directions of database security in the context of Internet information management. Topics covered include: Access control models for DBMSs, Inference controls, XML database security, Encrypted databases, Digital credentials and PKIs, Trust in open systems, and Peer-to-peer system security.", + "preclusion" : null, + "prerequisite" : "CS3223 Database Systems Implementation" + }, + "CS4231" : { + "moduleCode" : "CS4231", + "title" : "Parallel and Distributed Algorithms", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This course will examine some fundamental issues in parallel programming and distributed computing, and the relationships between the two. Parallel programming: mutual exclusion, semaphores, consistency, wait-free synchronization. Distributed computing: time, global state, snapshots, message ordering. Relationships: consensus, fault-tolerance, transactions, self-stabilization.", + "preclusion" : null, + "prerequisite" : "CS3230 Design and Analysis of Algorithms or CS3210 Parallel Computing" + }, + "CP5010" : { + "moduleCode" : "CP5010", + "title" : "Graduate Research Paper", + "moduleCredit" : "0", + "semesters" : [ 1, 2 ], + "description" : "The graduate research paper presentation is for evaluating the ability of the student to undertake a critical review of an existing research area. The student is expected to have necessary background and show competence in embarking on the PhD research. Students are expected to identify a promising research area. The paper should be self-contained and provide a good overview of the research problems, initial exploration of the research area, and insight to the research problems, with preliminary study and proposals on the outstanding research issues. It should contain more findings than a survery paper.", + "preclusion" : null, + "prerequisite" : null + }, + "CS4232" : { + "moduleCode" : "CS4232", + "title" : "Theory of Computation", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The objective of this module is to provide students with a theoretical understanding of what can be computed, and an introduction to the theory of complexity. It aims to introduce (1) some standard formal models of computation so as to develop an understanding of what can or cannot be computed by various computing devices; (2) some reasoning techniques commonly used in computer science; these include model equivalence, non-determinism, digitalisation, simulation and reduction; and (3) the mathematical formulation of objects in computer science so as to study their properties.", + "preclusion" : null, + "prerequisite" : "CS1231 or CS1231S or any level-2 MA module" + }, + "CS4350" : { + "moduleCode" : "CS4350", + "title" : "Game Development Project", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The objective of this project-based module is to provide an opportunity for the students to work in a group to design and develop a game following the main stages of game development process. The module will focus on the design of core dynamic, game mechanics, strategy, progression, balancing, game levels, interface and technical features including 3D graphics, animation, AI, physics, and networking. In addition, software engineering principles will be practised in developing the game software.", + "preclusion" : null, + "prerequisite" : "CS3247 or NM3216" + }, + "CSA6770" : { + "moduleCode" : "CSA6770", + "title" : "Graduate Research Seminar", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This is a required module for all PhD candidates in Cultural Studies in Asia programme. It is a forum for candidates to engage each other in critical discussion of their dissertation and other research projects. Each candidate is required to present a formal research paper. Active participation from each is expected. The module will be graded Satisfactory/Unsatisfactory' on the basis of a candidate's presentation and participation in discussions throughout the semester.", + "preclusion" : null, + "prerequisite" : null + }, + "CM1131" : { + "moduleCode" : "CM1131", + "title" : "Physical Chemistry 1", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Equations of state of ideal and real gases, intermolecular forces; kinetic theory of gases; first law of thermodynamics; enthalpy; thermochemistry; the second law; entropy; Helmholtz and Gibbs functions; the third law; rates of chemical reactions; accounting for the rate laws - reaction mechanisms; effect of temperature on reaction rate; theories of reaction rates.", + "preclusion" : null, + "prerequisite" : "'A' level or H2 pass in Chemistry or equivalent" + }, + "CP3209" : { + "moduleCode" : "CP3209", + "title" : "Undergraduate Research Project in Computing", + "moduleCredit" : "8", + "semesters" : [ 1, 2 ], + "description" : "This year-long module provides an opportunity for students to undertake a substantial research project under the supervision of faculty members of the School of Computing. Through this research collaboration, the student will experience first-hand the challenges and exhilaration of research, discovery and invention.", + "preclusion" : null, + "prerequisite" : "Completed 60MCs" + }, + "CP3208" : { + "moduleCode" : "CP3208", + "title" : "Undergraduate Research in Computing I", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The module (together with CP3209) is part of the UROP (Computing) project. The objective of this module and the UROP (Computing) project in general, is to provide an opportunity for talented students to undertake a substantial research project under the supervision of faculty members of the School of Computing. Through this research collaboration, the student will get to experience at first hand the challenges and exhilaration of research, discovery and invention. This module should be followed by CS3209 to complete the UROP (Computing) project.", + "preclusion" : "CS3208", + "prerequisite" : "SoC students who have passed at least 60 MCs and with approval from respective department." + }, + "CS5439" : { + "moduleCode" : "CS5439", + "title" : "Software Security", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Software engineering processes need to include security considerations in the modern world. This module familiarizes students to security issues in different stages of the software life-cycle. At the end of the module, the students are expected to understand secure programming practices, be able to analyse and check for impact of malicious inputs in programs, and employ specific testing techniques which can help detect software vulnerabilities.", + "preclusion" : "CS4239", + "prerequisite" : "CS3235 and (CS2103 or its equivalent)" + }, + "TR3202S" : { + "moduleCode" : "TR3202S", + "title" : "Start-up Internship Programme", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "This module documents the learning experience from the internship in writing. Taken together with TR3201 Entrepreneurship Practicum, the student will prepare a weekly logbook as well as internship reports which will be used a part of the evaluation of their internship experience.", + "preclusion" : "TR3102", + "prerequisite" : null + }, + "TR3202T" : { + "moduleCode" : "TR3202T", + "title" : "Start-up Internship Programme", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "This module documents the learning experience from the internship in writing. Taken together with TR3201 Entrepreneurship Practicum, the student will prepare a weekly logbook as well as internship reports which will be used a part of the evaluation of their internship experience.", + "preclusion" : "TR3102", + "prerequisite" : null + }, + "CS4226" : { + "moduleCode" : "CS4226", + "title" : "Internet Architecture", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module aims to focus on advanced networking concepts pertaining to the modern Internet architecture and applications. It covers a range of topics including network performance (throughput, delay, Little’s Law and M/M/1 queuing formula), and resource allocation and buffer management (max-min fair, round-robin and RED), intra- and inter-domain routing (RIP, OSPF and BGP), congestion control and modern variations of TCP (AIMD and Cubic TCP), peer-to-peer applications and content delivery networks (BitTorrent, Skype, Akamai), and data center networking and management (SDN and OpenFlow).", + "preclusion" : null, + "prerequisite" : "(CS2105 or EE3204 or EE4204) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS4347" : { + "moduleCode" : "CS4347", + "title" : "Sound and Music Computing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces the fundamental technologies employed in Sound and Music Computing focusing on three major categories: speech, music, and environmental sound. This module introduces the concept of sound and its representations in the analog and digital domains, as well as in time and frequency domains. Moreover, this module provides hands-on instruction on relevant machine learning tools, and an in-depth review of related technologies in sound data analytics (Automatic Speech Recognition, Automatic Music Transcription and Sound Event Detection) leading to a group project. Topics in sound synthesis, automatic music generation and music information retrieval will be covered for breadth.", + "preclusion" : null, + "prerequisite" : "CS2108 and \n(MA1101R or MA1311 or MA1508E or MA1513) and \n(MA1102R or MA1505 or MA1507 or (MA1511 and MA1512) or MA1521)" + }, + "CS4224" : { + "moduleCode" : "CS4224", + "title" : "Distributed Databases", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module studies the management of data in a distributed environment. It covers the fundamental principles of distributed data management and includes distribution design, data integration, distributed query processing and optimization, distributed transaction management, and replication. It will also look at how these techniques can be adapted to support database management in emerging technologies (e.g., parallel systems, peer-to-peer systems, cloud computing).", + "preclusion" : "CS5424", + "prerequisite" : "CS3223" + }, + "CS1101S" : { + "moduleCode" : "CS1101S", + "title" : "Programming Methodology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the concepts of programming and computational problem solving, and is the first and foremost introductory module to computing. Starting from a small core of fundamental abstractions, the module introduces programming as a method for communicating computational processes. The module begins with purely functional programming based on a simple substitution-based execution model, and ends with a powerful modern imperative language based on a realistic environment-based execution model. Topics covered include: functional abstraction, recursion, higher-order functions, data abstraction, algorithmic strategies, state mutation, loops and arrays, evaluation strategies, sorting and searching, debugging and testing.", + "preclusion" : "CS1010 or its equivalents", + "prerequisite" : null + }, + "CS4225" : { + "moduleCode" : "CS4225", + "title" : "Big Data Systems for Data Science", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Data science incorporates varying elements and builds on techniques and theories from many fields, including statistics, data engineering, data mining, visualization, data warehousing, and high-performance computing systems with the goal of extracting meaning from big data and creating data products. Data science utilizes advanced computing systems such as Apache Hadoop and Spark to address big data challenges. In this module, students will learn various computing systems and optimization techniques that are used in data science with emphasis on the system building and algorithmic optimizations of these techniques.", + "preclusion" : "BT4221 and CS5425", + "prerequisite" : "CS2102 or IT2002" + }, + "CS4222" : { + "moduleCode" : "CS4222", + "title" : "Wireless Networking", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide solid foundation for students in the area of wireless networks and introduces students to the emerging area of cyber-physical-system/Internet-of-Things. The module will cover wireless networking across all layers of the networking stack including physical, link, MAC, routing and application layers. Different network technologies with different characteristic will also be covered, including cellular networks, Wi-Fi, Bluetooth and ZigBee. Some key concepts that cut across all layers and network types are mobility management, energy efficiency, and integration of sensing and communications. The module emphasizes on exposing students to practical network system issues through building software prototypes.", + "preclusion" : "CS5422", + "prerequisite" : "(CS2105 or EE3204/E or EE4204) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS4223" : { + "moduleCode" : "CS4223", + "title" : "Multi-core Architectures", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The world of parallel computer architecture has gone through a significant transformation in the recent years from high-end supercomputers used only for scientific applications to the multi-cores (multiple processing cores on a single chip) that are ubiquitous in mainstream computing systems including desktops, servers, and embedded systems. In the context of this exciting development, the aim of this module is to examine the design issues that are critical to modern parallel architectures. Topics include instruction-level parallelism through static and dynamic scheduling, shared memory, message-passing, and data parallel computer architectures, cache coherence protocols, hardware synchronization primitives, and memory consistency models.", + "preclusion" : null, + "prerequisite" : "(CS2106 Operating Systems or CG2271 Realtime Operating Systems) and (CS3210 Parallel Computing or CS3220 Computer Architecture or CG3207 Computer Architecture)." + }, + "TR3202N" : { + "moduleCode" : "TR3202N", + "title" : "Start-up Internship Programme", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "This module documents the learning experience from the internship in writing. Taken together with TR3201 Entrepreneurship Practicum, the student will prepare a weekly logbook as well as internship reports which will be used a part of the evaluation of their internship experience.", + "preclusion" : "TR3102", + "prerequisite" : null + }, + "CS1231" : { + "moduleCode" : "CS1231", + "title" : "Discrete Structures", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces mathematical tools required in the study of computer science. Topics include: (1) Logic and proof techniques: propositions, conditionals, quantifications. (2) Relations and Functions: Equivalence relations and partitions. Partially ordered sets. Well-Ordering Principle. Function equality. Boolean/identity/inverse functions. Bijection. (3) Mathematical formulation of data models (linear model, trees, graphs). (4) Counting and Combinatoric: Pigeonhole Principle. Inclusion-Exclusion Principle. Number of relations on a set, number of injections from one finite set to another, Diagonalisation proof: An infinite countable set has an uncountable power set; Algorithmic proof: An infinite set has a countably infinite subset. Subsets of countable sets are countable.", + "preclusion" : "MA1100, CS1231S", + "prerequisite" : "A-level Mathematics or H2 Mathematics or MA1301 or MA1301FC or MA1301X" + }, + "CS4220" : { + "moduleCode" : "CS4220", + "title" : "Knowledge Discovery Methods in Bioinformatics", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The advent of high throughput technologies (e.g., DNA chips, microarray), biologists are being overloaded with information (e.g., gene expression data). A systematic way is needed to analyze the data to make sense of them. This module is introduced to provide students with knowledge of techniques that can be used to analyse biological data to enable them to discover new knowledge. At the end of the module, students will be able to identify the relevant techniques for different biological data to uncover new information. Topics include: Clustering analysis, classification, association rule mining; support vector machines; Hidden Markov Models.", + "preclusion" : null, + "prerequisite" : "CS2220 or LSM2241" + }, + "CS2040S" : { + "moduleCode" : "CS2040S", + "title" : "Data Structures and Algorithms", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces students to the design and\nimplementation of fundamental data structures and\nalgorithms. The module covers basic data structures\n(linked lists, stacks, queues, hash tables, binary heaps,\ntrees, and graphs), searching and sorting algorithms, and\nbasic analysis of algorithms.", + "preclusion" : "CS1020, CS1020E, CS2020, CS2010, CS2040, CS2040C", + "prerequisite" : "(MA1100 or (CS1231 or its equivalent)) and (CS1010 or its equivalent)" + }, + "CS4221" : { + "moduleCode" : "CS4221", + "title" : "Database Applications Design and Tuning", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module addresses the design and performance tuning of\ndatabase applications. The syllabus focusses on relational database applications implemented with relational database management systems. Topics covered include normalisation theory (functional, multi-valued and join dependency, normal forms, decomposition and synthesis methods), entityrelationship approach and SQL tuning (performance evaluation, execution plan verification, indexing, de-normalization, code level and transactions tuning). The syllabus optionally includes selected topics in the technologies, design and performance tuning of non-relational database applications (for instance, network and hierarchical models and nested relational model for an historical perspective, as well as XML and NoSQL systems for a modern perspective).", + "preclusion" : "CS5421", + "prerequisite" : "CS3223" + }, + "CS6244" : { + "moduleCode" : "CS6244", + "title" : "Advanced Topics in Robotics", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module presents the advances in robotics research over a broad range of topics such as robot perception, learning, decision making and control, and human-robot interaction. The exact topics of focus may differ in each offering. Through this module, students will get familiar with recent research trends and developments in robotics and prepare for research in robotics and related fields.", + "preclusion" : null, + "prerequisite" : "CS3230 and \n(MA1101R or MA1311 or MA1506 or MA1508E) and\n(ST2131 or ST2334)" + }, + "TR3202I" : { + "moduleCode" : "TR3202I", + "title" : "Start-up Internship ProgrammeStart-up Internship Programme", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "This module documents the learning experience from the internship in writing. Taken together with TR3201 Entrepreneurship Practicum, the student will prepare a weekly logbook as well as internship reports which will be used a part of the evaluation of their internship experience.", + "preclusion" : "TR3102", + "prerequisite" : null + }, + "CS2040" : { + "moduleCode" : "CS2040", + "title" : "Data Structures and Algorithms", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces students to the design and implementation of fundamental data structures and algorithms. The module covers basic data structures (linked lists, stacks, queues, hash tables, binary heaps, trees, and graphs), searching and sorting algorithms, and basic analysis of algorithms.", + "preclusion" : "CS1020, CS1020E, CS2020, CS2010, CS2040C, CS2040S", + "prerequisite" : "CS1010 or its equivalent" + }, + "CS6240" : { + "moduleCode" : "CS6240", + "title" : "Multimedia Analysis", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide a comprehensive and rigorous treatment of the main approaches in multimedia (document, image, video, graphics) analysis. Three main themes are covered: (1) representation and modelling of multimedia entities using various modelling approaches, (2) matching of a model with an input entity, and (3) derivation of a model from sample entities. It focuses on the non-vector-space approach, which complements the vector-space approach to multimedia analysis.", + "preclusion" : null, + "prerequisite" : "CS4243 or CS5240" + }, + "CP5103" : { + "moduleCode" : "CP5103", + "title" : "Master of Computing Project", + "moduleCredit" : "8", + "semesters" : [ 1, 2 ], + "description" : "The project option provides individual students the\nopportunity and experience to work on a significant\ncomputing project. It aims to prepare students with\nsufficient practical and/or research experiences in the\ncomputing field. The project will be carried out under the\nsupervision of an academic staff. The selection of the\ntopic will be done in consultation with the supervisor. All\nprojects will be vetted by the School. The project will be\nassessed through a written project report and will be\nletter-graded.", + "preclusion" : "CP5101 (MComp Dissertation), CP5102 (MComp\nInformation Security Project) or any project/ dissertation\nmodule.", + "prerequisite" : "Students must be in Master of Computing programme." + }, + "PC1143" : { + "moduleCode" : "PC1143", + "title" : "Introduction to Electricity & Magnetism", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module covers the fundamentals of electricity and magnetism: electric fields, electric flux and Gauss's law, electric potential; capacitance, dielectrics, current and resistance; DC circuits; magnetic fields, magnetic effect of currents, Ampere's law, electromagnetic induction; AC circuits; magnetism in matter; electromagnetic waves. The module also has a practical component consisting of five experiments designed to enhance students' understanding of some of the concepts discussed in lectures. This module is targeted at science students who wish to acquire a working knowledge in electricity and magnetism, and is an essential for physics majors.", + "preclusion" : "Students who have passed PC1432/PC1432X are not allowed to take this module.", + "prerequisite" : "‘A' level or H2 pass in Physics or PC1221/PC1221FC/PC1221X & PC1222/PC1222X" + }, + "CP5104" : { + "moduleCode" : "CP5104", + "title" : "Graduate Project in Computing", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The objective of this project module is to allow graduate students an opportunity to undertake a substantial project work over a semester. Students may work individually on projects proposed by staff, possibly in collaboration with\nexternal companies. The students will have good opportunity to apply what they have learnt to some technical challenges or practical problems, be it researchoriented or software-development. The project will be assessed through a written project report and will be letter-graded.", + "preclusion" : "CP5101", + "prerequisite" : "Student must be enrolled in a postgraduate programme." + }, + "PC1144" : { + "moduleCode" : "PC1144", + "title" : "Introduction to Modern Physics", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces the ideas of modern physics to students, with an emphasis on conceptual understanding. Topics covered are a) Einstein's theory of special relativity, including time dilation, length contraction, and his famous equation E=mc2, b) Quantum physics, where the observed phenomena of black body radiation, the photoelectric effect and Compton scattering, leading to the quantization of angular momentum and energy, atomic transitions and atomic spectra, c) Introduction to quantum mechanics, introducing the Heisenberg uncertainty principle, wave-mechanics and wave particle duality, and the use of wavefunctions in predicting the behaviour of particles trapped in potential wells, d) Nuclear physics, introducing radioactivity and decay processes, nuclear interaction and binding energy, fission and fusion, and e) Sub-atomic elementary particles and their classification. The module is targeted at science students who are interested in learning about the more recent developments in physics, and is an essential for physics majors.", + "preclusion" : "Students who have passed PC1432/PC1432X are not allowed to take this module.", + "prerequisite" : "‘A' level or H2 pass in Physics or PC1221/PC1221FC/PC1221X & PC1222/PC1222X" + }, + "PC1141" : { + "moduleCode" : "PC1141", + "title" : "Introduction to Classical Mechanics", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module presents the fundamental principles of classical mechanics. It covers such topics as kinematics, Galilean transformation, Newton's laws of motion, dynamics of a particle with generalization to many particle systems, conservation laws, collisions, angular momentum and torque, motion of a rigid body, gravitation and planetary motion, static equilibrium, oscillatory motion and vibrational modes, waves, Doppler's effect and fluid mechanics. The module also has a practical component consisting of five experiments designed to enhance students' understanding of some of the concepts discussed in lectures. This module is targeted at science students who wish to acquire a working knowledge of mechanics, and is an essential for physics majors.", + "preclusion" : "STUDENTS WHO HAVE PASSED PC1431 OR PC1431FC or PC1431X OR PC1433 ARE NOT ALLOWED TO TAKE THIS MODULE.", + "prerequisite" : "‘A' level or H2 pass in Physics or PC1221/PC1221FC/PC1221X & PC1222/PC1222X" + }, + "CM1417" : { + "moduleCode" : "CM1417", + "title" : "Fundamentals of Chemistry", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The objective of this module is to provide an introduction to the fundamental topics and concepts of chemistry. This includes topics like structure of matter, periodicity and the periodic table, chemical Bonding, states of matter, stoichiometry and equilibrium, reaction types, kinetics, organic chemistry, including such topics as functional groups and isomerism.", + "preclusion" : "A level or H2 Chemistry or equivalent or CM1417X", + "prerequisite" : "'O' Level pass in Chemistry or equivalent" + }, + "PC1142" : { + "moduleCode" : "PC1142", + "title" : "Introduction to Thermodynamics and Optics", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module covers the fundamentals of two branches of physics: thermodynamics and optics. Its aim is to prepare students for a host of more advanced modules in these and related areas. Topics included in the part on thermodynamics are thermal processes and effects, the first and second laws, kinetic theory of gases, heat engines and entropy. The part on optics encompasses topics such as geometric optics, systems of lenses, optical instruments, interference, diffraction, grating and polarization. The module also has a practical component consisting of five experiments designed to enhance students' understanding of some of the concepts discussed in lectures. This module is targeted at science students who wish to acquire a working knowledge of thermodynamics and optics, and is an essential for physics majors.", + "preclusion" : "STUDENTS WHO HAVE PASSED PC1431 OR PC1431FC or PC1431X ARE NOT ALLOWED TO TAKE THIS MODULE.", + "prerequisite" : "‘A' level or H2 pass in Physics or PC1221/PC1221FC/PC1221X & PC1222/PC1222X" + }, + "CP3201" : { + "moduleCode" : "CP3201", + "title" : "Industry Seminar", + "moduleCredit" : "2", + "semesters" : [ 1 ], + "description" : "The information technology (IT) industry is in an everchanging state of evolvement and innovation. This module aims to acquaint students with the latest Information\nTechnology (IT) innovation, practices, and developments. Prominent leaders and practitioners in the IT industry will be invited to impart their knowledge and insights into the latest IT trends and developments from various industry arenas such as the finance, healthcare, consulting, manufacturing, and entertainment industries. Students' performance will be graded as \"Completed Satisfactory/Completed Unsatisfactory (CS/CU)\" at the end of the module based on the coursework.", + "preclusion" : null, + "prerequisite" : "Students can only take this module after completing 70 MCs" + }, + "CP5101" : { + "moduleCode" : "CP5101", + "title" : "MComp Dissertation", + "moduleCredit" : "16", + "semesters" : [ 1, 2 ], + "description" : "The dissertation option gives individual students the opportunity for independent study and research in the area of their selected specialization. This will be carried out under the supervision of an academic staff, and the selection of the topic/area will be done in consultation with the supervisor in the area of expertise.", + "preclusion" : "- CP5102 (MComp Information Security Project - 8MC)\n- CP5103 (Master of Computing Project – 8MC)\n- CP5104 (Graduate Project in Computing – 4MC)", + "prerequisite" : null + }, + "CP5102" : { + "moduleCode" : "CP5102", + "title" : "MComp Information Security Project", + "moduleCredit" : "8", + "semesters" : [ 1, 2 ], + "description" : "The exploratory project option gives individual students the opportunity for independent study and research in the area of their selected specialization. This will be carried out under the supervision of an academic staff, in possible cosupervision with a mentor from the industry or government agency. The selection of the topic/area will be done in consultation with the supervisor and the external mentor. All projects will be vetted by School of Computing Postgraduate Office.", + "preclusion" : null, + "prerequisite" : "Students must be in Master of Computing programme, Infocomm Security specialisation" + }, + "CM1121" : { + "moduleCode" : "CM1121", + "title" : "Organic Chemistry 1", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module covers the characteristic properties, methods of preparation, and reactions of alkanes/cycloalkanes, alkenes, alkynes, benzene and other aromatic compounds, alkyl halides; alcohols; ethers; epoxides, phenols, aldehydes and ketones; carboxylic acids and their derivatives; amines.", + "preclusion" : "CM1501 or CM1503 or CM1401", + "prerequisite" : "'A' level or H2 pass in Chemistry or equivalent or CM1417/CM1417X" + }, + "CS2040C" : { + "moduleCode" : "CS2040C", + "title" : "Data Structures and Algorithms", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces students to the design and implementation of fundamental data structures and algorithms. The module covers basic data structures (linked lists, stacks, queues, hash tables, binary heaps, trees, and graphs), searching and sorting algorithms, basic analysis of algorithms, and basic object-oriented programming concepts.", + "preclusion" : "CS1020, CS1020E, CS2020, CS2010, CS2040, CS2040S", + "prerequisite" : "CS1010 or its equivalent" + }, + "CP3108A" : { + "moduleCode" : "CP3108A", + "title" : "Independent Work", + "moduleCredit" : "2", + "semesters" : [ 1, 2 ], + "description" : "", + "preclusion" : "CS3108A", + "prerequisite" : null + }, + "CP3108B" : { + "moduleCode" : "CP3108B", + "title" : "Independent Work", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "", + "preclusion" : "CS3108B", + "prerequisite" : null + }, + "CS4218" : { + "moduleCode" : "CS4218", + "title" : "Software Testing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module covers the concepts and practice of software testing including unit testing, integration testing, and regression testing. Various testing coverage criteria will be discussed. Debugging methods for finding the root-cause of errors in failing test cases will also be investigated. The use of testing and analysis for performance prediction, performance clustering and performance debugging will be studied. Students will acquire crucial skills on testing and debugging through hands-on assignments.", + "preclusion" : null, + "prerequisite" : "CS3219 Software Engineering Principles and Patterns." + }, + "CS3247" : { + "moduleCode" : "CS3247", + "title" : "Game Development", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The objective of this module is to introduce techniques for electronic game design and programming. This module covers a range of important topics including 3D maths, game physics, game AI, sound, as well as user interface for computer games. Furthermore, it will give an overview of computer game design to the students. Through laboratory programming exercises, the students will have hands-on programming experience with popular game engines and will develop basic games using those engines.", + "preclusion" : null, + "prerequisite" : "CS3241" + }, + "CS4215" : { + "moduleCode" : "CS4215", + "title" : "Programming Language Implementation", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module provides the students with theoretical knowledge and practical skill in the implementation of programming languages. It discusses implementation aspects of fundamental programming paradigms (imperative, functional and object-oriented), and of basic programming language concepts such as binding, scope, parameter-passing mechanisms and types. It introduces the language processing techniques of interpretation and compilation and virtual machines. The lectures are accompanied by lab sessions which will focus on language processing tools, and take the student through a sequence of programming language implementations. This modules\nalso covers automatic memory management, dynamic linking and just-in-time compilation, as features of modern execution systems.", + "preclusion" : null, + "prerequisite" : "(CS2010 or its equivalent) or CS2020 or (((CS2030 or its equivalent) or CS2113/T) and ((CS2040 or its equivalent)))" + }, + "CS5425" : { + "moduleCode" : "CS5425", + "title" : "Big Data Systems for Data Science", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Data science incorporates varying elements and builds on techniques and theories from many fields, including statistics, data engineering, data mining, visualization, data warehousing, and high-performance computing systems with the goal of extracting meaning from big data and creating data products. Data science needs advanced computing systems such as Apache Hadoop and Spark to address big data challenges. In this module, students will learn various computing systems and optimization techniques that are used in data science with emphasis on the system building and algorithmic optimizations of these techniques.", + "preclusion" : "BT4221 and CS4225", + "prerequisite" : "CS2102" + }, + "CS3245" : { + "moduleCode" : "CS3245", + "title" : "Information Retrieval", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module discusses the basic concepts and methods of information retrieval including capturing, representing, storing, organizing, and retrieving unstructured or loosely structured information. The most well-known aspect of information retrieval is document retrieval: the process of indexing and retrieving text documents. However, the field of information retrieval includes almost any type of\nunstructured or semi-structured data, including newswire stories, transcribed speech, email, blogs, images, or video. Therefore, information retrieval is a critical aspect of Web search engines. This module also serves as the foundation for subsequent modules on the understanding, processing and retrieval of particular web media.", + "preclusion" : null, + "prerequisite" : "(CS2010 or its equivalent) or CS2020 or (CS2040 or its equivalent)" + }, + "CS5424" : { + "moduleCode" : "CS5424", + "title" : "Distributed Databases", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module studies the management of data in a distributed environment. It covers the fundamental principles of distributed data management and includes distribution design, data integration, distributed query processing and optimization, distributed transaction management, and replication. It will also look at how these techniques can be adapted to support database management in emerging technologies (e.g., parallel systems, peer-to-peer systems, cloud computing).", + "preclusion" : "CS4224", + "prerequisite" : "CS3223" + }, + "CS3243" : { + "moduleCode" : "CS3243", + "title" : "Introduction to Artificial Intelligence", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The module introduces the basic concepts in search and knowledge representation as well as to a number of sub-areas of artificial intelligence. It focuses on covering the essential concepts in AI. The module covers Turing test, blind search, iterative deepening, production systems, heuristic search, A* algorithm, minimax and alpha-beta procedures, predicate and first-order logic, resolution refutation, non-monotonic reasoning, assumption-based truth maintenance systems, inheritance hierarchies, the frame problem, certainly factors, Bayes' rule, frames and semantic nets, planning, learning, natural language, vision, and expert systems and LISP.", + "preclusion" : "EEE and CPE students can only take this module as a technical elective to satisfy the program requirements or UEM but not CFM/ULR-Breadth.", + "prerequisite" : "((CS2010 or its equivalent) or CS2020 or (CS2040 or its equivalent))\nand (MA1100 or (CS1231 or its equivalent))" + }, + "CS4211" : { + "moduleCode" : "CS4211", + "title" : "Formal Methods for Software Engineering", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Before software can be designed, its requirements must be well understood. This in turns requires a thorough understanding of the application domain. Based on the requirements, software engineers construct design models, and then use these design models as guide to construct software implementations. This module will cover formal specification and verification techniques for accurately capturing and reasoning about requirements, model and code. The topics covered include modeling notations, temporal logics, model checking, software model checking, theorem proving, and symbolic execution based analysis. Most importantly, the module will attempt to inculcate an appreciation and understanding of formal thinking in software design and construction.", + "preclusion" : null, + "prerequisite" : "CS2103 or its equivalent" + }, + "CS5422" : { + "moduleCode" : "CS5422", + "title" : "Wireless Networking", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide solid foundation for students in the area of wireless networks and introduces students to the emerging area of cyber-physical-system/Internet-of-Things. The module will cover wireless networking across all layers of the networking stack including physical, link, MAC, routing and application layers. Different network technologies with different characteristic will also be covered, including cellular networks, Wi-Fi, Bluetooth and ZigBee. Some key concepts that cut across all layers and network types are mobility management, energy efficiency, and integration of sensing and communications. The module emphasizes on exposing students to practical network system issues through building software prototypes.", + "preclusion" : "CS4222", + "prerequisite" : "(CS2105 or EE3204/E or EE4204) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS3244" : { + "moduleCode" : "CS3244", + "title" : "Machine Learning", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces basic concepts and algorithms in machine learning and neural networks. The main reason for studying computational learning is to make better use of powerful computers to learn knowledge (or regularities) from the raw data. The ultimate objective is to build self-learning systems to relieve human from some of already-too-many programming tasks. At the end of the course, students are expected to be familiar with the theories and paradigms of computational learning, and capable of implementing basic learning systems.", + "preclusion" : "BT4240, DMX1401AI or its equivalents, IT3011", + "prerequisite" : "(CS2010 or CS2020 or CS2040 or its equivalent) and \n(MA1101R or MA1311 or MA1508E or MA1513) and \n(MA1102R or MA1505 or MA1507 or (MA1511 and MA1512) or MA1521) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS4212" : { + "moduleCode" : "CS4212", + "title" : "Compiler Design", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The objective of this module is to introduce the principal ideas behind program compilation, and discusses various techniques for program parsing, program analysis, program optimisation, and run-time organisation required for program execution. Topics covered include regular expressions, context-free grammars, lexical analysis, syntax analysis; different algorithms for parsing codes, such as top-down parsing, bottom-up parsing; translation to abstract syntax using modern parser generator technology, intermediate representation, semantics analysis, type system, un-optimised code generation, code optimisation, data-flow analysis, instruction scheduling.", + "preclusion" : null, + "prerequisite" : "CS2104 Programming Language" + }, + "CS5421" : { + "moduleCode" : "CS5421", + "title" : "Database Applications Design and Tuning", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module addresses the design and performance tuning of database applications. The syllabus focuses on relational database applications implemented with relational database management systems. Topics covered include normalisation theory (functional, multi-valued and join dependency, normal forms, decomposition and synthesis methods), entity relationship approach and SQL tuning (performance evaluation, execution plan verification, indexing, de-normalization, code level and transactions tuning). The syllabus optionally includes selected topics in the technologies, design and performance tuning of nonrelational database applications (for instance, network and hierarchical models and nested relational model for an historical perspective, as well as XML and NoSQL systems for a modern perspective).", + "preclusion" : "CS4221", + "prerequisite" : "CS3223" + }, + "CS6235" : { + "moduleCode" : "CS6235", + "title" : "Advanced Topics in Theoretical Computer Science", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This graduate-level module covers advanced topics in the theoretical aspects of computer science that are of current research or application interests. Topics falling under this module include algorithms, theory of computation, formal models, and semantics. The exact topic may vary from year to year and depends on the instructor teaching the module. Upon completion of this module, the student will\nhave a deeper understanding on some of the latest research problems in one of the areas of theoretical computer science. This module will help prepare students towards doing research in theoretical computer science.", + "preclusion" : null, + "prerequisite" : "CS3230" + }, + "CS3241" : { + "moduleCode" : "CS3241", + "title" : "Computer Graphics", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module teaches some graphics hardware devices, reviews the mathematics related to the understanding, and discusses the fundamental areas of computer graphics. After completing the course, students are expected to understand the basic computer graphics terminology and concepts, and to be able to design and implement simple 2D and 3D interactive computer graphics related programs. As an enrichment part of the course, students are introduced the state-of-the-art development in computer graphics by viewing interesting video clips and experimenting with demo program made available in the course web.", + "preclusion" : "EEE and CPE students can only take this module as a technical elective to satisfy the program requirements or UEM but not CFM/ULR-Breadth.", + "prerequisite" : "(CS2010 or its equivalent) or CS2020 or (((CS2030 or its equivalent) or CS2113/T) and ((CS2040 or its equivalent)))" + }, + "CS6234" : { + "moduleCode" : "CS6234", + "title" : "Advanced Algorithms", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module is aimed at graduate students who are doing or intend to do advanced research in algorithms design and analysis in all areas of computer science. The module covers advanced material on combinatorial and graph algorithms with emphasis on efficient algorithms, and explores their use in a variety of application areas. Topics covered include, but are not restricted to, linear programming, graph matching and network flows, approximation algorithms, randomized algorithms, online algorithms, local search algorithms, algorithms for large datasets. The module will be a seminar-based module that will expose students to current research in these areas.", + "preclusion" : null, + "prerequisite" : "CS5234" + }, + "CS3242" : { + "moduleCode" : "CS3242", + "title" : "3D Modeling and Animation", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide fundamental concepts in 3D modeling and animation. It also serves as a bridge to advanced media modules. After taking this module, students should be able to use these concepts to easily build or work with digital models, manipulate the models by means of computer deformation and animation, and use lighting and rendering techniques to create appealing scenes. Topics include coordinate spaces, transforms, 3D model representations, hierarchical structures, deformation, procedural modelling, particle systems, character animation, shading networks, lighting, and scripting concepts.", + "preclusion" : "CS4342", + "prerequisite" : "CS3241 and (PC1221 or PC1221X) and \n(MA1101R or MA1311 or MA1508E or MA1513) and \n(MA1102R or MA1505 or MA1507 or (MA1511 and MA1512) or MA1521)" + }, + "CS3240" : { + "moduleCode" : "CS3240", + "title" : "Interaction Design", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This course is intended for students in computing and related disciplines whose work focuses on human-computer interaction issues in the design of computer systems. The course stresses the importance of user-centred design and usability in the development of computer applications and systems. Students will be taken through the analysis, design, development, and evaluation of human-computer interaction methods for computer systems. They will acquire hands-on design skills through laboratory exercises and assignments. The course also covers HCI design principles and emphasizes the importance of contextual, organisational, and social factors in system design.", + "preclusion" : null, + "prerequisite" : "(CS1020 or its equivalent) or CS2020 or (CS2030 or its equivalent) or CS2113/T or NM3209 or NM2207/Y" + }, + "CS6231" : { + "moduleCode" : "CS6231", + "title" : "Advanced Topics in Security and Privacy", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module aims to prepare PhD students for research in security and privacy, by investigating security issues in various theoretical as well as system computer science areas such as software, networks, data analytics and machine learning, etc. It addresses security and privacy concepts and design principles from an adversarial perspective. Selected topics in security and privacy are covered, such as software security, applied cryptography, privacy-preserving data analysis, and design of secure distributed systems. Emerging topics of current research interests may be included as well.", + "preclusion" : null, + "prerequisite" : "CS4236 Cryptography Theory and Practice or \nCS3235 Computer Security or \nCS5231 System Security." + }, + "CS2030" : { + "moduleCode" : "CS2030", + "title" : "Programming Methodology II", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module is a follow up to CS1010. It explores two modern programming paradigms, object-oriented programming and functional programming. Through a series of integrated assignments, students will learn to develop medium-scale software programs in the order of thousands of lines of code and tens of classes using objectoriented design principles and advanced programming constructs available in the two paradigms. Topics include\nobjects and classes, composition, association, inheritance, interface, polymorphism, abstract classes, dynamic binding, lambda expression, effect-free programming, first class functions, closures, continuations, monad, etc.", + "preclusion" : "CS2030S", + "prerequisite" : "CS1010 or its equivalent" + }, + "IS1103" : { + "moduleCode" : "IS1103", + "title" : "Ethics in Computing", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module gives an introduction to Ethics in the Computing domain. Students will learn about the importance of Ethics in Computing policy-making and be able to make judgements and decisions based on established ethical frameworks (such as Deontology, Consequentialism, Social Contract Theory and Virtue Ethics). The objective is to develop students to be ethical computing decision-makers who can analyse and explain their decisions in real-world policy-making situations. Issues in emerging areas such as Digital Intellectual Property Rights, Artificial Intelligence, Big Data, Social Media, Hacking, and interface design may also be discussed in relation to Ethics.", + "preclusion" : null, + "prerequisite" : null + }, + "CS5260" : { + "moduleCode" : "CS5260", + "title" : "Neural Networks and Deep Learning II", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module is a follow-up to CS5242 and covers\nadvanced topics in neural networks and deep learning.\nThis module explores the underlying mechanism of a\nvariety of different types of learning models: unsupervised,\nsemi-supervised, and adversarial learning models, that\nare not covered in CS5242. Topics may include:\ngenerative adversarial networks, adversarial machine\nlearning, zero-shot learning, geometric deep learning,\nneural architecture search.", + "preclusion" : null, + "prerequisite" : "CS5242 Neural Networks and Deep Learning" + }, + "PC1432" : { + "moduleCode" : "PC1432", + "title" : "Physics IIE", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces fundamental concepts of physics and is illustrated with many practical examples. Topics covered include a) Electricity and magnetism, where the basic concepts of electric and magnetic fields, forces on charged particles, electric potential, electromotive force, work and energy, are described. The properties of basic electrical circuits comprising resistors, inductors and capacitors are discussed, along with analysis of their transient and steady-state behaviour. Understanding the role of Maxwell's equations in electromagnetism is emphasized; b) Waves, introducing properties of waves, including geometric optics, propagation, interference and diffraction, and electromagnetic waves; and c) Quantum physics, where new physics concepts which led to the quantization of energy are introduced, leading to an explanation of atomic transitions, atomic spectra and the physical and the chemical properties of the atom. The uncertainty principle, wave-mechanics and wave particle duality concepts are covered, together with the use of wavefunctions in predicting the behaviour of trapped particles. The module is targeted essentially at Engineering students.", + "preclusion" : "Students majoring in Physics or students who have passed in PC1143 or PC1144 or PC1432X are not allowed to take this module.", + "prerequisite" : "Students from FOE ( i.e. Computer Eng, Common Engineering, Bioengineering, Industrial & Systems Eng and Material Science & Eng) with ‘A’ level or H2 pass in Physics; or 'A' level or H2 pass in Physics; or PC1221/PC1221FC/PC1221X & PC1222/PC1222X" + }, + "LSM1106" : { + "moduleCode" : "LSM1106", + "title" : "Molecular Cell Biology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The objective is to provide the student with a firm and rigorous foundation in current concepts of the structure and functions of biomolecules in molecular cellular biology. These fundamental concepts form the basis of almost all recent advances in biological and the biomedical sciences. The lectures will introduce various cellular organelles as models to gain insights into how structures and functions of classes of biomolecules participating in important cellular processes.", + "preclusion" : "LSM1101", + "prerequisite" : "GCE ‘A’ Level or H2 Biology or equivalent, or LSM1301 or LSM1301X" + }, + "LSM1105" : { + "moduleCode" : "LSM1105", + "title" : "Evolutionary Biology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "Evolutionary biology covers the history of life on our planet and the processes that produced the multiple life forms of Earth. Topics include: the origins of life, the eukaryotic cell, and multicellularity; the generation of genetic variation and the sorting of that variation through random processes and through natural and sexual selection; the origin of new traits, new life histories, and new species; the origins of sex, sociality, and altruism; the evolution of humans; and applications of evolutionary biology to solving modern-day problems.", + "preclusion" : "YSC2216", + "prerequisite" : "GCE 'A' Level or H2 Biology or equivalent, or LSM1301 or LSM1301X" + }, + "CS1010X" : { + "moduleCode" : "CS1010X", + "title" : "Programming Methodology", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces the fundamental concepts of problem solving by computing and programming using an imperative programming language. It is the first and foremost introductory course to computing and is equivalent to CS1010, CS1010S and CS1010E Programming Methodology. The module will be taught using the Python programming language and topics covered include problem solving by computing, writing pseudo-codes, basic problem formulation and problem solving, program development, coding, testing and debugging, fundamental programming constructs (variables, types, expressions, assignments, functions, control structures, etc.), fundamental data structures: arrays, strings and structures, simple file processing, and basic recursion.", + "preclusion" : "CS1010 or its equivalent, CS1010FC", + "prerequisite" : null + }, + "CS2309" : { + "moduleCode" : "CS2309", + "title" : "CS Research Methodology", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "", + "preclusion" : "CS2305S", + "prerequisite" : "(CS2010 or its equivalent) or CS2020 or ((CS2030 or its equivalent) or CS2113/T) and (CS2040 or its equivalent))\nand \n(MA1100 or (CS1231 or its equivalent))" + }, + "LSM1102" : { + "moduleCode" : "LSM1102", + "title" : "Molecular Genetics", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module covers topics on (i) the patterns of inheritance, (ii) the molecular properties of genes and chromosomes, (iii) transcription and translation, (iv) genetic methods and technology, and (v) genetic analysis of individuals and populations. This will include an in-depth understanding of mendelian patterns of inheritance and variations that could occur due to multiple alleles, lethal genes, chromosomal variations, linkage, gene interaction and other genetic phenomena. Emphasis is placed on the understanding of the underlying molecular and biochemical basis of inheritance. Quantitative and population genetics will also be discussed with the emphasis of understanding the processes and forces in nature that promote genetic changes.", + "preclusion" : "YSC2233", + "prerequisite" : "GCE 'A' Level or H2 Biology or equivalent, or LSM1301 or LSM1301X" + }, + "CS1010R" : { + "moduleCode" : "CS1010R", + "title" : "Programming Methodology", + "moduleCredit" : "1", + "semesters" : [ 1 ], + "description" : "This 1-MC module adds a research component to the host module, enabling students to acquire more in-depth understanding of the research issues pertaining to the subject matter.", + "preclusion" : "CG1101, CS1010, CS1010E, CS1101, CS1101C, CZ1102, IT1002, Engineering students", + "prerequisite" : "Co-read with host module in current semester or pass host module in previous semester. Student selection process is enforced." + }, + "CS1010S" : { + "moduleCode" : "CS1010S", + "title" : "Programming Methodology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the fundamental concepts of problem solving by computing and programming using an imperative programming language. It is the first and \nforemost introductory course to computing and is equivalent to CS1010 and CS1010E Programming Methodology. Topics covered include problem solving by computing, writing pseudo-codes, basic problem formulation and problem solving, program development, coding, testing and debugging, fundamental programming constructs (variables, types, expressions, assignments, functions, control structures, etc.), fundamental data structures: arrays, strings and structures, simple file processing, and basic recursion. This module is appropriate for FoS students.", + "preclusion" : "CS1010, CS1010E, CS1010J, CS1010X, CS1010XCP, CS1101S", + "prerequisite" : null + }, + "CS3236" : { + "moduleCode" : "CS3236", + "title" : "Introduction to Information Theory", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces the basics of modern information theory. It covers how information can be quantified, and what this quantification tells us about how well we can compress and transmit information without error. It discusses basic error correcting techniques, and information-theoretic cryptography. Topics covered\ninclude: mathematical techniques, entropy measures, fundamental limits to data compression and noisy-channel coding, examples of error-correcting codes, examples of information theoretic cryptography (commitments, secure computation, key distribution, randomness extraction).", + "preclusion" : null, + "prerequisite" : "(MA1100 or (CS1231 or its equivalent)) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS3237" : { + "moduleCode" : "CS3237", + "title" : "Introduction to Internet of Things", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The Internet of Things (IoT), where a large number of physical objects embedded with computing power and sensors connect to the network for seamless cooperation between the cyber domain and the physical world, is revolutionizing our lives. This module will serve as an introduction to the IoT and provide a holistic view of the entire spectrum of the IoT system architecture from the devices to the fog and the cloud computing. The focus will be on designing IoT systems that balance both the functional and non-functional (communication bandwidth, security, safety, power) requirements. The module will have a significant project component.", + "preclusion" : null, + "prerequisite" : "(CS1010 or equivalent) and (CG2028 or CS2100 or EE2024 or EE2028)" + }, + "CS3234" : { + "moduleCode" : "CS3234", + "title" : "Logic for Proofs and Programs", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces logic as a means for specifying and solving computational problems. It explores how logic can be used to represent computational problems, how these representations can be proven correct, and how they can be executed on a computer. Students learn about logic as formal systems (semantic, axiomatic, and deductive) and how to write proofs in the different systems. They also learn how to use a proof assistant such as Coq and how to program in a logic programming language such as Prolog. Topics include classical and intuitionistic logic, SAT, Peano’s axioms, Hoare logic, and other selected logic systems.", + "preclusion" : null, + "prerequisite" : "MA1100 or (CS1231 or its equivalent); Programming experience is preferred." + }, + "CS3235" : { + "moduleCode" : "CS3235", + "title" : "Computer Security", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The objective of this module is to provide a broad understanding of computer security with some indepth discussions on selected topics in system and network security. This module covers the following topics: intrusion detection, DNS security, electronic mail security, authentication, access control, buffer overflow, memory and stack protection, selected topics in application security, for instance, web security, and well-known attacks.", + "preclusion" : null, + "prerequisite" : "(CS2105 or EE3204 or EE4204) and (CS2106 or CG2271) and CS2107" + }, + "CS3241R" : { + "moduleCode" : "CS3241R", + "title" : "Computer Graphics", + "moduleCredit" : "1", + "semesters" : [ 1 ], + "description" : "This module teaches some graphics hardware devices, reviews the mathematics related to the understanding, and discusses the fundamental areas of computer graphics. After completing the course, students are expected to understand the basic computer graphics terminology and concepts, and to be able to design and implement simple 2D and 3D interactive computer graphics related programs. As an enrichment part of the course, students are introduced the state-of-the-art development in computer graphics by viewing interesting video clips and experimenting with demo program made available in the course web.", + "preclusion" : null, + "prerequisite" : "Co-read with host module in current semester or pass host module in previous semester. Student selection process is enforced." + }, + "CS3233" : { + "moduleCode" : "CS3233", + "title" : "Competitive Programming", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to prepare students in competitive problem solving. It covers techniques for attacking and solving challenging computational problems. Fundamental algorithmic solving techniques covered include divide and conquer, greedy, dynamic programming, backtracking and branch and bound. Domain specific techniques like number theory, computational geometry, string processing and graph theoretic will also be covered. Advanced AI search techniques like iterative deepening, A* and heuristic search will be included. The module also covers algorithmic and programming language toolkits used in problem solving supported by the solution of representative or well-known problems in the various algorithmic paradigms.", + "preclusion" : null, + "prerequisite" : "At least grade A- in (CS2010 or CS2020 or (both CS2030 and CS2040)) or special permission" + }, + "CS2030S" : { + "moduleCode" : "CS2030S", + "title" : "Programming Methodology II", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module is a follow up to CS1010. It explores two modern programming paradigms, object-oriented programming and functional programming. Through a series of integrated assignments, students will learn to develop medium-scale software programs in the order of thousands of lines of code and tens of classes using object-oriented design principles and advanced programming constructs available in the two paradigms. Topics include objects and classes, composition, association, inheritance, interface, polymorphism, abstract classes, dynamic binding, lambda expression, effect-free programming, first class functions, closures, continuations, monad, etc.", + "preclusion" : "CS2030", + "prerequisite" : "CS1010 or its equivalent" + }, + "CS3230" : { + "moduleCode" : "CS3230", + "title" : "Design and Analysis of Algorithms", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces different techniques of designing and analysing algorithms. Students will learn about the framework for algorithm analysis, for example, lower bound arguments, average case analysis, and the theory of NP-completeness. In addition, students are exposed to various algorithm design paradigms. The module serves two purposes: to improve the students' ability to design algorithms in different areas, and to prepare students for the study of more advanced algorithms. The module covers lower and upper bounds, recurrences, basic algorithm paradigms (such as prune-and-search, dynamic programming, branch-and-bound, graph traversal, and randomised approaches), amortized analysis, NP-completeness, and some selected advanced topics.", + "preclusion" : "EEE and CPE students can only take this module as a technical elective to satisfy the program requirements or UEM but not CFM/ULR-Breadth.", + "prerequisite" : "((CS2010 or its equivalent) or CS2020 or (CS2040 or its equivalent)) and (MA1100 or (CS1231 or its equivalent))" + }, + "CP6010" : { + "moduleCode" : "CP6010", + "title" : "Doctoral Seminar", + "moduleCredit" : "0", + "semesters" : [ 1, 2 ], + "description" : "A PhD candidate will be required to give a Doctoral Seminar within 12 months after passing his/her PhD Thesis Proposal. The seminar, which should include any research findings or work from published papers.", + "preclusion" : null, + "prerequisite" : null + }, + "CS6101" : { + "moduleCode" : "CS6101", + "title" : "Exploration of Computer Science Research", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces CS graduate students to various research areas in Computer Science. Study groups are organised for major research areas. Each study group provides a forum for students to read, present and discuss\nresearch papers, and acquire the basic research skills for literature review and critical comparison of existing work. Students will also gain a first experience in technical presentation and writing. This module will be graded as “Completed Satisfactory” or “Completed Unsatisfactory” (CS/CU).", + "preclusion" : null, + "prerequisite" : null + }, + "DMC1401CS" : { + "moduleCode" : "DMC1401CS", + "title" : "Design Your Own Module", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "", + "preclusion" : null, + "prerequisite" : null + }, + "CS6220" : { + "moduleCode" : "CS6220", + "title" : "Advanced Topics in Data Mining", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "With the rapid advances of computer and internet technologies, a large amount of data accumulates. Discovering knowledge from the data will give us a competitive advantage. The process of knowledge discovery involves pre-processing the data, mining or discovering patterns from the data, and post-processing the discovered patterns. In this course, we will review and examine the present techniques and the theories behind them and explore new and improved techniques for real world knowledge discovery applications. The course is designed to encourage active discussion, creative thinking, and hands-on project development.", + "preclusion" : null, + "prerequisite" : "CS5228" + }, + "CS5250" : { + "moduleCode" : "CS5250", + "title" : "Advanced Operating Systems", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The module covers a broad range of issues in the design and implementation of modern advanced operating systems. The topics covered in this module includes OS design strategies (including microkernels, mobile, embedded and real-time operating systems and the component’s interfaces), priority and resource allocation strategies; scheduling algorithms (including for multi-core, multi-processors); naming, protection and security; UI and windowing systems; file system implementations (including network and distributed file systems); failure and recovery; and virtualization and the Internet-ready OS. They extend and provide in-depth coverage of material in earlier prerequisite OS modules.", + "preclusion" : null, + "prerequisite" : "CS2106 Introduction to Operating Systems or CG2271\nReal-Time Operating Systems" + }, + "CP2106" : { + "moduleCode" : "CP2106", + "title" : "Independent Software Development Project (Orbital)", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "Orbital provides a platform for students to gain hands-on industrial experience for computing technologies related to students’ own interests. Done in pairs of two, Orbital students propose, design, execute, implement and market their project to peers and faculty. Peer assessment and critique of others’ projects are key components of the modules’ deliverables.", + "preclusion" : "CS2103 Software Engineering or its equivalent", + "prerequisite" : "CS1010 Programming Methodology or its equivalent" + }, + "CS6219" : { + "moduleCode" : "CS6219", + "title" : "Advanced Topics in Computer Systems", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This graduate-level module covers advanced topics in computer systems that are of current research or application interests. Topics include operating systems,\nsystems architecture and hardware, distributed systems, computer networks, and the interaction between these areas. The exact topics to be taught will depend on the lecturers teaching the module. Upon completion of this module, the student will have a deeper understanding on some of the latest research problems in the area of computer systems, as well as the state-of-the-art approaches to address the problems. This module will help prepare students towards doing research in computer systems.", + "preclusion" : null, + "prerequisite" : "CS2105 and CS2106" + }, + "CS3223" : { + "moduleCode" : "CS3223", + "title" : "Database Systems Implementation", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This system-oriented module provides an in-depth study of the concepts and implementation issues related to database management systems. It first covers the physical implementation of the relational data model, which includes storage management, access methods, query processing, and optimisation. Then it covers issues and techniques dealing with multi-user application environments, namely, transactions, concurrency control, and recovery. The third part covers advanced topics such as on-line analytical processing, in-memory databases, and column stores.", + "preclusion" : null, + "prerequisite" : "((CS2010 or its equivalent) or CS2020 or (CS2040 or its equivalent)) and (CS2102 or IT2002)" + }, + "CS6216" : { + "moduleCode" : "CS6216", + "title" : "Advanced Topics in Machine Learning", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This graduate level module covers advanced topics in\nmachine learning that are of current research or\napplication interests. The exact topics to be taught will\ndepend on the lecturers teaching the module. Upon\ncompletion of this module, the student will have a deeper\nunderstanding on some of the latest research problems in\nmachine learning as well as the state-of-the-art\napproaches and solutions. This module will help prepare\nstudents towards doing research in machine learning.", + "preclusion" : null, + "prerequisite" : "CS3244" + }, + "CS3103" : { + "moduleCode" : "CS3103", + "title" : "Computer Networks Practice", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module aims to provide an opportunity for the students to learn commonly-used network protocols in greater technical depth with their implementation details than a basic networking course. Students will perform hands-on experiments in configuring and interconnecting LANs using networking devices/technologies (e.g., routers, switches, SDN switches, and hubs), networking protocols (e.g., DHCP, DNS, RIP, OSPF, ICMP, TCP, UDP, wireless LAN, VLAN protocols, SIP, SSL, IPSec-VPN) and networking tools (e.g, tcpdump, netstat, ping, traceroute). Students will learn higher-layer network protocols and develop network applications (client/server, P2P) via socket programming.", + "preclusion" : null, + "prerequisite" : "CS2105 or EE3204/E or EE4204" + }, + "CS3230R" : { + "moduleCode" : "CS3230R", + "title" : "Design and Analysis of Algorithms", + "moduleCredit" : "1", + "semesters" : [ 1 ], + "description" : "This 1-MC module adds a research component to the host module, enabling students to acquire more in-depth understanding of the research issues pertaining to the subject matter.", + "preclusion" : null, + "prerequisite" : "Co-read host module. Student selection process is enforced." + }, + "CS6215" : { + "moduleCode" : "CS6215", + "title" : "Advanced Topics in Program Analysis", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "Program analysis techniques allow one to automatically\nanalyse the behaviour of a computer program, to identify\nbugs and performance bottlenecks. This graduate level\nmodule covers advanced topics in program analysis that\nare of current research or application interests. Students\nwill explore the state-of-the-art techniques and systems for\nprogram analysis. After taking the module, students will\nbe able to apply advanced automated program analysis\ntools and techniques to verify, test, and debug programs,\nas well as be better prepared for conducting research in\nprogram analysis and apply them in related research\nareas.", + "preclusion" : null, + "prerequisite" : "CS3230 and CS4212" + }, + "CS1010J" : { + "moduleCode" : "CS1010J", + "title" : "Programming Methodology", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module introduces the fundamental concepts of problem solving by computing and programming using an imperative programming language. It is the first and foremost introductory course to computing. Topics covered include computational thinking and computational problem solving, designing and specifying an algorithm, basic problem formulation and problem solving approaches, program development, coding, testing and debugging, fundamental programming constructs (variables, types, expressions, assignments, functions, control structures, etc.), fundamental data structures (arrays, strings, composite data types), basic sorting, and recursion.", + "preclusion" : "CS1010 and its equivalents", + "prerequisite" : null + }, + "CS4277" : { + "moduleCode" : "CS4277", + "title" : "3D Computer Vision", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "One of the most important capability for robots such as self-driving cars, domestic mobile robots, and drones to achieve full autonomy is the ability to perceive the 3D environment. A camera is an excellent choice as the main sensory device for robotic perception because it produces information-rich images, and is lightweight, low cost and requires little or no maintenance. This module covers the mathematical concepts and algorithms that allow us to recover the 3D geometry of the camera motions and the structures in its environment. Topics include projective geometry, camera model, one-/two-/three-/N-View reconstructions and stereo, generalized cameras and non- rigid structure-from-motion.", + "preclusion" : "CS5477", + "prerequisite" : "(MA1101R or MA1311 or MA1506 or MA1508E) and (CS2040 or its equivalent)" + }, + "CS4278" : { + "moduleCode" : "CS4278", + "title" : "Intelligent Robots: Algorithms and Systems", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces the core algorithms and system architectures of intelligent robots. It examines the main system components for sensing, decision making, and motion control and importantly, their integration for core robot capabilities, such as navigation and manipulation. It covers the key algorithms for robot intelligence through inference, planning, and learning, and also provides some practical experiences with modern robot systems. A variety of Illustrative examples are given, e.g., self-driving cars, aerial drones, and object manipulation.", + "preclusion" : "CS5478", + "prerequisite" : "CS3243 and (MA1101R or MA1311 or MA1508E) and (MA1102R or MA1505 or (MA1511 and MA1512) or MA1521) and (EE2012/A or ST2131 or ST2334)" + }, + "CS6213" : { + "moduleCode" : "CS6213", + "title" : "Special Topics in Distributed Computing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "", + "preclusion" : null, + "prerequisite" : "CS3211 or CS4231" + }, + "CS4276" : { + "moduleCode" : "CS4276", + "title" : "IoT Security", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "With the advent of the Internet-of-Things, the computing paradigm is quickly changing from the traditional cyber domain to cyber-physical domain. This is made possible from devices that are equipped with sensors and actuators that interact with the physical world. In this module, we will investigate how such sensing systems affect the notion of computer security. We will also explore the state-of-the-art research in the areas of sensing systems and how they can provide benefits to the security of the Internet-of-Things. This module will also investigate how an attacker may compromise the sensing information to exploit security vulnerabilities in these systems.", + "preclusion" : "CS5476", + "prerequisite" : "CG3002 or CG4002 or CS3237" + }, + "CS6211" : { + "moduleCode" : "CS6211", + "title" : "Analytical Performance Modelling for Computer Systems", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "Constructing simple mathematical models to describe a computer system can help in analysis and understanding of the characteristics, behaviour, and performance of the system. This module introduces students to the modelling techniques, commonly used models, applications of the models to performance modelling of computer systems, and experimental validation of the models. After completing the module, students are expected to have the confidence to construct, analyse, and validate a performance model for a computer system that they are interested in.", + "preclusion" : null, + "prerequisite" : "(ST2334 or ST2131) and CS2105 and CS2106." + }, + "CM1417X" : { + "moduleCode" : "CM1417X", + "title" : "Fundamentals of Chemistry", + "moduleCredit" : "4", + "semesters" : [ 2, 3 ], + "description" : "The objective of this module is to provide an introduction to the fundamental topics and concepts in chemistry. This includes topics such as structure of matter, periodic table and periodicity, chemical bonding, states of matter, stoichiometry, reaction types, kinetics, equilibrium and introduction to organic chemistry.", + "preclusion" : "Students with ‘A’ level or H2 Chemistry or equivalent.\nor CM1417", + "prerequisite" : "’O’ level pass in chemistry or equivalent" + }, + "CS5242" : { + "moduleCode" : "CS5242", + "title" : "Neural Networks and Deep Learning", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module provides students with the knowledge of deep neural network and enables them to apply deep learning methods effectively on real world problems. The module emphasizes on the understanding of the principles of neural networks and deep learning; practical guidelines and techniques for deep learning; and their applications. Through assignments and projects, students will design, develop, and evaluate deep learning-based solutions to practical problems, such as those in the areas of computer vision, bioinformatics, fintech, cybersecurity, and games.", + "preclusion" : null, + "prerequisite" : "CS3244 Machine Learning" + }, + "CS6210" : { + "moduleCode" : "CS6210", + "title" : "The Art of Computer Science Research", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide the meta-skills for research in computer science. How does one discover great research problems? What are the good strategies for solving research problems? How does one write papers or give presentations with great impact? Students will seek answers to these questions by critically examining and assessing successful and less successful examples of\nresearch.", + "preclusion" : null, + "prerequisite" : "CS3230 Design and Analysis of Algorithms" + }, + "CS5240" : { + "moduleCode" : "CS5240", + "title" : "Theoretical Foundations in MultiMedia", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The module lays the theoretical foundation for graduate students to do research in multimedia: images, videos, audio, speech, graphics and text documents. The module covers the main theoretical issues common to various multimedia research. These issues provide a general framework within which specific techniques in particular research areas can be understood. Topics include: vector and signal representations of multimedia, spatial and frequency analyses, models and parameter estimation methods. Examples will be drawn from different types of media. Upon completion, students will be well-grounded to pursue further research in computer vision, graphics, natural language processing, audio analysis and multimedia applications.", + "preclusion" : null, + "prerequisite" : "((CS1020 or its equivalent) or CS2020 or (CS2040 or its equivalent)) and (MA1101R or MA1311 or MA1508E or MA1513) and \n(MA1102R or MA1505 or MA1507 or (MA1511 and MA1512) or MA1521) and \n(EE2012/A or MA2216 or ST1131/A or ST1232 or ST2131 or ST2334)" + }, + "CS1010E" : { + "moduleCode" : "CS1010E", + "title" : "Programming Methodology", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the fundamental concepts of problem solving by computing and programming using an imperative programming language. It is the first and foremost introductory course to computing. Topics covered include computational thinking and computational problem solving, designing and specifying an algorithm, basic problem formulation and problem solving approaches, program development, coding, testing and debugging, fundamental programming constructs (variables, types, expressions, assignments, functions, control structures, etc.), fundamental data structures (arrays, strings, composite data types), basic sorting, and recursion.", + "preclusion" : "CS1010, CS1010J, CS1010S, CS1010X, CS1010XCP, CS1101S", + "prerequisite" : null + }, + "CS3219" : { + "moduleCode" : "CS3219", + "title" : "Software Engineering Principles and Patterns", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module provides an in-depth, hands-on experience in key aspects of software engineering that accompany the development of software. Based on proven principles and best practices, this module focuses on software architectural design from the perspective of the software process. It covers techniques for requirement elicitation and specification that provide sound base for architectural design. The module covers design decision exploration as well as patterns that explicate principles and best practices in replicable form.", + "preclusion" : "CS3213 Software Systems Design", + "prerequisite" : "CS2103 or its equivalent" + }, + "MA1101R" : { + "moduleCode" : "MA1101R", + "title" : "Linear Algebra I", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module is a first course in linear algebra. Fundamental concepts of linear algebra will be introduced and investigated in the context of the Euclidean spaces R^n. Proofs of results will be presented in the concrete setting. Students are expected to acquire computational facilities and geometric intuition with regard to vectors and matrices. Some applications will be presented. Major topics: Systems of linear equations, matrices, determinants, Euclidean spaces, linear combinations and linear span, subspaces, linear independence, bases and dimension, rank of a matrix, inner products, eigenvalues and eigenvectors, diagonalization, linear transformations between Euclidean spaces, applications.", + "preclusion" : "EG1401, EG1402, MA1101, MA1311, MA1506, MA1508, FOE students, YSC2232", + "prerequisite" : "GCE ‘A’ Level or H2 Mathematics or H2 Further Mathematics or MA1301 or MA1301FC or MA1301X" + }, + "CS3216" : { + "moduleCode" : "CS3216", + "title" : "Software Product Engineering for Digital Markets", + "moduleCredit" : "5", + "semesters" : [ 1 ], + "description" : "In this module, students will practice software product engineering by working in small teams to develop well-tested, user-friendly, production-quality software for the real world. To support this goal, students work closely with users to understand their problems, gather their requirements, and obtain their feedback through a rapid, iterative, application design and development process. Students will also be exposed to practical issues for digital markets such as growing the user base of their application, deployment of the application on the Web or in the cloud system, and validating the UI design and UX of the application.", + "preclusion" : null, + "prerequisite" : "CS2103 or its equivalent or with special approval from instructor. Students will submit personal statements to apply for a place in the course instead of bidding through the CORS system." + }, + "CS3217" : { + "moduleCode" : "CS3217", + "title" : "Software Engineering on Modern Application Platforms", + "moduleCredit" : "5", + "semesters" : [ 2 ], + "description" : "This module introduces students to the practice of software engineering on modern application platforms such as mobile devices, the Web and cloud systems. Students will work in small project teams to develop well-tested,\nproduction-quality software. This module focuses on building core software engineering skills and competencies in programming modern application platforms. It also trains students to work well in project teams. Students will be\nassessed on both their individual programming competencies and their software enginnering skills in final team project.", + "preclusion" : null, + "prerequisite" : "CS2103 or its equivalent or with special approval from instructor. Students will submit personal statements to apply for a place in the course instead of bidding through the CORS system." + }, + "CS6208" : { + "moduleCode" : "CS6208", + "title" : "Advanced Topics in Artificial Intelligence", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module covers advanced topics in artificial intelligence that are of current research or application interests. A wide range of topics may be covered including soft computing (fuzzy logic, genetic algorithms, etc.), data mining, machine learning, image and video processing, artificial life, robotics, etc. The exact topics to be taught will depend on the lecturers teaching the module.", + "preclusion" : null, + "prerequisite" : "CS3243" + }, + "ES2660" : { + "moduleCode" : "ES2660", + "title" : "Communicating in the Information Age", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "In a context of prolific production and convenient access to content and innovation in the Information Age, how should one critically process and clearly communicate ideas to various audiences? In this module, students will learn to question and articulate their analysis of assumptions and assertions on issues facing the Information Age through processes such as identifying bias and substantiating arguments. The Ennis’ (1986, 2001) taxonomy of critical thinking dispositions will be employed to develop students’ analytical thinking skills and their ability to articulate cogent responses to arguments or to defend their own positions in both written and oral form.", + "preclusion" : "GET1006 and GEK1901", + "prerequisite" : "1. Students who are required to take ES1000 Foundation Academic English and/or ES1103 English for Academic Purposes, must pass those modules before they are allowed to read this module.\n2. Only SoC students matriculated in AY2016/2017 and after, are allowed to take ES2660." + }, + "CS5239" : { + "moduleCode" : "CS5239", + "title" : "Computer System Performance Analysis", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The objective of this module is to provide students a working knowledge of computer performance evaluation and capacity planning. They will be able to identify performance bottlenecks, to predict when performance limits of a system will be exceeded, and to characterise present and future workload to perform capacity planning activities. Topics include: performance analysis overview; measurement techniques and tools including workload characterisation, instrumentation, benchmarking, analytical modelling techniques including operational analysis, stochastic queuing network analysis; performance of client-server architectures; capacity planning; case studies.", + "preclusion" : null, + "prerequisite" : "((CS1020 or its equivalent) or CS2020 or (CS2030 or its equivalent) or CS2113/T) and (EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS6207" : { + "moduleCode" : "CS6207", + "title" : "Advanced Natural Language Processing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The module aims to prepare students to embark on research in natural language processing (NLP). At the end of the course, the students will have experience in reading and critiquing research papers, and will have undertaken a substantial project on some aspects of NLP research. Topics covered include: Statistical parsing, Word sense disambiguation, SENSEVAL, co-reference resolution, machine translation, question answering.", + "preclusion" : null, + "prerequisite" : "CS4248" + }, + "CS4268" : { + "moduleCode" : "CS4268", + "title" : "Quantum Computing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module will introduce basics of quantum computing and cover various well known algorithms e.g. Deutsch-Jozsa algorithm, Simon’s algorithms, quantum Fourier transform, phase estimation, order finding, Shor’s algorithm and Grover’s algorithm. The module will also cover some basics in quantum information theory, cryptography and error correction.", + "preclusion" : null, + "prerequisite" : "CS3230 and \n(MA1101R or MA1311 or MA1508E or MA1513) and \n(EE2012/A or MA2216 or ST2131 or ST2334)" + }, + "CS5236" : { + "moduleCode" : "CS5236", + "title" : "Advanced Automata Theory", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "In computer science, automata are an important tool for many theoretical investigations. Various types of automata have been used to characterise complexity classes. This module covers automata theory in depth, describes the\nChomsky hierarchy, and introduces various advanced topics including automata structures, automata on infinite words, automata on trees and the learnability of classes of regular languages from queries and positive data.", + "preclusion" : null, + "prerequisite" : "CS4232 Theory of Computation" + }, + "CS5478" : { + "moduleCode" : "CS5478", + "title" : "Intelligent Robots: Algorithms and Systems", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module introduces the core algorithms and system architectures of intelligent robots. It examines the main system components for sensing, decision making, and motion control and importantly, their integration for core robot capabilities, such as navigation and manipulation. It covers the key algorithms for robot intelligence through inference, planning, and learning, and also provides some practical experiences with modern robot systems. A variety of Illustrative examples are given, e.g., self-driving cars, aerial drones, and object manipulation.", + "preclusion" : "CS4278", + "prerequisite" : "CS3243 and (MA1101R or MA1311 or MA1508E) and (MA1102R or MA1505 or (MA1511 and MA1512) or MA1521) and (EE2012/A or ST2131 or ST2334)" + }, + "CS3210" : { + "moduleCode" : "CS3210", + "title" : "Parallel Computing", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "The aim of this module is to provide an introduction to the field of parallel computing with hands-on parallel programming experience on real parallel machines. The module is divided into four parts: parallel computation models and parallelism, parallel architectures, parallel algorithm design and programming, and new parallel computing models. Topics includes: theory of parallelism and models; shared-memory architectures; distributed-memory architectures; data parallel architectures; interconnection networks, topologies and basic of communication operations; principles of parallel algorithm design; performance\nand scalability of parallel programs, overview of new parallel computing models such as grid, cloud, GPGPU.", + "preclusion" : null, + "prerequisite" : "CS2100 or CG2007 or CG2028 or EE2024 or EE2028" + }, + "CS5477" : { + "moduleCode" : "CS5477", + "title" : "3D Computer Vision", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "One of the most important capability for robots such as\nself-driving cars, domestic mobile robots, and drones to\nachieve full autonomy is the ability to perceive the 3D\nenvironment. A camera is an excellent choice as the main\nsensory device for robotic perception because it produces\ninformation-rich images, and is lightweight, low cost and\nrequires little or no maintenance. This module covers the\nmathematical concepts and algorithms that allow us to\nrecover the 3D geometry of the camera motions and the\nstructures in its environment. Topics include projective\ngeometry, camera model, one-/two-/three-/N-View\nreconstructions and stereo, generalized cameras and nonrigid structure-from-motion.", + "preclusion" : "CS4277", + "prerequisite" : "(MA1101R or MA1311 or MA1506 or MA1508E) and\n(CS2040 or its equivalent)" + }, + "CS6203" : { + "moduleCode" : "CS6203", + "title" : "Advanced Topics in Database Systems", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module covers the topics in data base management systems with current research and industrial interests and importance. Examples of topics include multimedia data management, object-oriented database technology, data warehousing and data mining, integration of heterogeneous and legacy systems.", + "preclusion" : null, + "prerequisite" : "CS3223" + }, + "CS3211" : { + "moduleCode" : "CS3211", + "title" : "Parallel and Concurrent Programming", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "A concurrent system consists of a set of processes that executes simultaneously and that may collaborate by communicating and synchronising with one another. Examples of concurrent systems are parallel programs that describe sets of collaborating processes. This module introduces the design, development and debugging of parallel programs. It will build on the concurrency concepts gained from the Operating Systems module. It covers concepts and modelling tools for specifying and reasoning (about the properties of) concurrent systems and parallel programs. It also covers principles of performance analysis, asynchronous and asynchronous parallel programming, and engineering concurrent systems and parallel programs.", + "preclusion" : null, + "prerequisite" : "CS2106 or CG2271" + }, + "CS5234" : { + "moduleCode" : "CS5234", + "title" : "Algorithms at Scale", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This course presents advanced techniques for the design and analysis of algorithms and data structures, with emphasis on efficiency and scalability. It will cover a variety of algorithmic topics that arise when coping with very large data sets. How do you design algorithms that scale well? How do you process streaming data? How do you construct algorithms that run efficiently on modern hardware? The goal of this module is to cover modern tools and techniques in algorithm design.", + "preclusion" : null, + "prerequisite" : "CS3230" + }, + "CS5476" : { + "moduleCode" : "CS5476", + "title" : "IoT Security", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "With the advent of the Internet-of-Things, the computing\nparadigm is quickly changing from the traditional cyber\ndomain to cyber-physical domain. This is made possible\nfrom devices that are equipped with sensors and actuators\nthat interact with the physical world. In this module, we will\ninvestigate how such sensing systems affect the notion of\ncomputer security. We will also explore the state-of-the-art\nresearch in the areas of sensing systems and how they\ncan provide benefits to the security of the Internet-ofThings. Furthermore, this module will also investigate how\nan attacker may compromise the sensing information to\nexploit security vulnerabilities in these systems.", + "preclusion" : "CS4276", + "prerequisite" : "CG3002 or CG4002 or CS3237" + }, + "CS5233" : { + "moduleCode" : "CS5233", + "title" : "Simulation and Modelling Techniques", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide students with a working knowledge of applying\nsimulation techniques to model, simulate and study complex systems. It covers techniques in simulation model design, model execution, and model analysis. Students will have hands-on experience using a simulation package. The module will also introduce concepts of parallel and distributed simulation, and high level architecture.", + "preclusion" : null, + "prerequisite" : "CS4231 and \n(EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS5232" : { + "moduleCode" : "CS5232", + "title" : "Formal Specification and Design Techniques", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The primary role of the formal specification is to provide a precise and unambiguous description of a computer system. A formal specification allows the system designer to verify important properties and detect design error before system development begins. The objective of this course is to study various formal specification and design techniques for modelling (1) object-oriented systems, (2) real-time distributed systems, and (3) concurrent reactive systems. The course will focus on the state-based notations Z/Object-Z, event-based notation CSP/Timed-CSP. Graphical modelling notations, such as StateChart and UML (Unified Modelling Language) will also be addressed.", + "preclusion" : null, + "prerequisite" : "(MA1100 or (CS1231 or its equivalent)) and CS2103" + }, + "CS5231" : { + "moduleCode" : "CS5231", + "title" : "Systems Security", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module introduces fundamental notions and requirements in computer system security and the mechanisms that provide security in various systems and applications. It aims to teach students the security perspective of popular computer systems, such as desktop systems, mobile systems, and web-based systems. Its topics include software security, operating system security, mobile security, web security, trusted platforms, and auditing and forensic analysis.", + "preclusion" : null, + "prerequisite" : "CS3235 Computer Security" + }, + "CS6285" : { + "moduleCode" : "CS6285", + "title" : "Topics in Computer Science: Bridging System and Deep Learning", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Co-design of system and machine learning algorithms has led to faster and more scalable machine learning systems. The module aims to expose students to recent state-of-the-art co-design techniques to make deep learning run faster, touching on both system research and AI research. The specific topics include distributed deep learning, large-batch training, second-order optimization, asynchronous algorithms, neural network compression, federated machine learning, memory-efficient optimizers, model parallelism, efficient communication library, low-precision training.", + "preclusion" : "Variable, depend on the choice of topics or departmental approval.", + "prerequisite" : "CS5242 and CS3210" + }, + "CS2113T" : { + "moduleCode" : "CS2113T", + "title" : "Software Engineering & Object-Oriented Programming", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the necessary skills for systematic and rigorous development of software systems. It covers requirements, design, implementation, quality assurance, and project management aspects of small-to-medium size multi-person software projects. The module uses the Object Oriented Programming paradigm. Students of this module will receive hands-on practice of tools commonly used in the industry, such as test automation tools, build automation tools, and code revisioning tools will be covered.", + "preclusion" : "CS2103, CS2103T, (CS2113T for CS2113), (CS2113 for CS2113T)", + "prerequisite" : "CS2040C or ((CS2030 or its equivalent) and CS2040/S)" + }, + "CS6283" : { + "moduleCode" : "CS6283", + "title" : "Topics in Computer Science: Trustworthy Machine Learning", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "Machine learning is increasingly being used in critical decision-making systems, yet is not reliable in the presence of noisy, biased, and adversarial data. Can we trust machine learning models? This module aims to answer this question, by covering the fundamental aspects of reasoning about trust in machine learning, including its robustness to adversarial data and model manipulations, the privacy risks of machine learning algorithms for sensitive data, the transparency measures for machine learning, and fairness in AI. It covers the algorithms that analyze machine learning vulnerabilities; and techniques for building reliable and trustworthy machine learning algorithms.", + "preclusion" : "Variable, depend on the choice of topics or departmental approval.", + "prerequisite" : "CS3244 Machine Learning" + }, + "PC1221" : { + "moduleCode" : "PC1221", + "title" : "Fundamentals of Physics I", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module aims to bridge the gap between O level physics and 1st year university physics level. The module covers the fundamentals of two branches of physics: mechanics and thermodynamics. Topics included in the part on mechanics are linear motion, curvilinear motion, relative motion, circular motion, Newtons laws of motion, work and energy, conservation of energy, linear momentum and conservation, rotational kinematics, torque and moment of inertia, rotational dynamics, conservation of angular momentum, gravitation and planetary motion, static equilibrium, oscillatory motion and fluid mechanics. The part on thermodynamics encompasses topics such as temperature and zeroth law of thermodynamics, temperature scales, thermal expansion, heat and internal energy, thermal processes, first law of thermodynamics, ideal gas laws and kinetic theory of gasses. .", + "preclusion" : "A' LEVEL OR H2 PASS IN PHYSICS OR PC1141, OR PC1142 OR PC1431 OR PC1431FC or PC1431X OR PC1221FC or PC1221X, YSC1213", + "prerequisite" : "'O' level pass in Physics or Combined Science (Physics & Chemistry OR Physics & Biology)." + }, + "CS6280" : { + "moduleCode" : "CS6280", + "title" : "Topics in Computer Science: Systems Design for Next Gen Hardware", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "With the end of Moore's Law, we are witnessing a paradigm shift in computing platforms towards the inclusion of specialized hardware accelerators. In this module, we will explore the designs of system software on these emerging computing hardware platforms. We will first take a broad overview of existing and upcoming specialized hardware devices, including GPU, TPU, FPGA, SmartNICs, reconfigurable network switches, and other specialized ASICs. We will then discuss various topics in systems design for these new hardware platforms, e.g., OS constructs, abstractions, programming models, resource sharing and multiplexing, scheduling, co-designing with applications and algorithms, and joint processing with CPU.", + "preclusion" : null, + "prerequisite" : "CS2100 Computer Organization and CS2106 Introduction to Operating Systems" + }, + "CP3880" : { + "moduleCode" : "CP3880", + "title" : "Advanced Technology Attachment Programme", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "", + "preclusion" : "EG3601", + "prerequisite" : "(IS2101 Business and Technical Communication or CS2101 Effective Communication for Computing Professionals or their equivalents)\nand\n(CS2103/CS2103T Software Engineering or IS2103 Enterprise Systems Development Concepts or IS2150 E-Business Design and Implementation or BT2101 IT and Decision Making)" + }, + "CSA6102" : { + "moduleCode" : "CSA6102", + "title" : "Cultural Studies in Asia", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This module will examine the various areas of research in Cultural Studies conducted by Asian scholars or scholars locating their research in Asia. It will examine the histories, concepts and analytic strategies that these scholars deploy in the analysis of the changing cultural landscapes and practices in contemporary Asia. Abiding themes of the module will be the conceptual constitution of the idea of 'Asia', the emergence of 'trans-Asian' practices and the possibility of 'pan-Asian' identities that these trans-location practices might engender.", + "preclusion" : null, + "prerequisite" : null + }, + "PC1222" : { + "moduleCode" : "PC1222", + "title" : "Fundamentals of Physics II", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The module aims to bridge the gap between O level Physics and first year university physics level. The module covers the fundamentals of three branches of physics: electricity & magnetism, optics and modern physics. Topics included in the part on electricity & magnetism are Coulombs law, electric field and potential, capacitance, current and resistance, DC circuits, magnetic fields, magnetic effects on current, electromagnetic induction, AC circuits and electromagnetic waves. The part on optics encompasses topics such as reflection and refraction, systems of lenses, optical instruments, interference, diffraction, grating and polarization. Topics covered in the part on modern physics are blackbody radiation, photoelectric effect, atomic transitions and spectra, the uncertainty principle, wave-particle duality, radioactivity and decay processes, binding energy and fusion energy and fusion & fission.", + "preclusion" : "'A' Level OR H2 Pass in Physics or PC1143, or PC1144 or PC1432/PC1432X, YSC1213", + "prerequisite" : "'O' level pass in Physics or Combined Science (Physics & Chemistry OR Physics & Biology)." + }, + "CP4106" : { + "moduleCode" : "CP4106", + "title" : "Computing Project", + "moduleCredit" : "8", + "semesters" : [ 1, 2 ], + "description" : "The objective of this project module enables students to undertake a substantial computing-related project work over a period of one year. Students work individually on self-proposed projects or projects proposed by staff. They will have good opportunity to apply what they have learnt on practical problems, be it research-oriented or software development-oriented. Students should periodically submit a report make a presentation to the respective supervisors.\nThe project will be letter-graded.", + "preclusion" : "CG4001, BT4101, CP4101, or any Integrated Honours Thesis/Project/Dissertation module", + "prerequisite" : "Completed at least 112 MCs for the respective degree." + }, + "MA1521" : { + "moduleCode" : "MA1521", + "title" : "Calculus for Computing", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module provides a basic foundation for calculus and its related subjects required by computing students. The objective is to train the students to be able to handle calculus techniques arising in their courses of specialization. In addition to the standard calculus material, the course also covers simple mathematical modeling techniques and numerical methods in connection with ordinary differential equations. \n\n\n\nMajor topics: \n\nPreliminaries on sets and number systems. \n\nCalculus of functions of one variable and applications. \n\nSequences, series and power series. \n\nFunctions of several variables. Extrema.\n\nFirst and second order differential equations. \n\nBasic numerical methods for ordinary differential equations.", + "preclusion" : "Students reading a primary major in Mathematics/Applied Mathematics/Quantitative Finance/Data Science and Analytics, MA1102R, MA1312, MA1505, MA1507, MA2501, FoE students, YSC1216", + "prerequisite" : "GCE ‘A’ Level Mathematics or H2 Mathematics or H2 Further Mathematics or MA1301 or MA1301X" + }, + "CS3236R" : { + "moduleCode" : "CS3236R", + "title" : "Introduction to Information Theory", + "moduleCredit" : "1", + "semesters" : [ 1 ], + "description" : "This 1-MC module adds a research component to the host module, enabling students to acquire more in-depth understanding of the research issues pertaining to the subject matter.", + "preclusion" : "same as CS3236", + "prerequisite" : "Co-read with host module in current semester or pass host module in previous semester. Student selection process is enforced." + }, + "CS5229" : { + "moduleCode" : "CS5229", + "title" : "Advanced Computer Networks", + "moduleCredit" : "4", + "semesters" : [ 1 ], + "description" : "This course covers advanced fundamental principles of computer networks and techniques for networking. The goal of this course is to teach these fundamentals/techniques that will remain important and relevant regardless of the hot topics in networks and networking. Briefly, the topics include advanced network architecture and design principles, protocol mechanisms, implementation principles and software engineering practices, network algorithmic, network simulation techniques and tools, performance analysis and measurement, and protocol specification/verification techniques.", + "preclusion" : null, + "prerequisite" : "CS4226 Internet Architecture or EE4210 Computer Communications Networks II" + }, + "CS2113" : { + "moduleCode" : "CS2113", + "title" : "Software Engineering & Object-Oriented Programming", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This module introduces the necessary skills for systematic and rigorous development of software systems. It covers requirements, design, implementation, quality assurance, and project management aspects of small-to-medium size multi-person software projects. The module uses the Object Oriented Programming paradigm. Students of this module will receive hands-on practice of tools commonly used in the industry, such as test automation tools, build automation tools, and code revisioning tools will be covered.", + "preclusion" : "CS2103, CS2103T, (CS2113T for CS2113), (CS2113 for CS2113T)", + "prerequisite" : "CS2040C or ((CS2030 or its equivalent) and CS2040/S)" + }, + "CS3203" : { + "moduleCode" : "CS3203", + "title" : "Software Engineering Project", + "moduleCredit" : "8", + "semesters" : [ 1, 2 ], + "description" : "This module provides students with hands-on experience in\nworking in project groups through a complete SDLC to\ndevelop a well-designed, well-tested, large-scaled software\nsystem. The students will apply the current best software\nengineering practices on the analysis, design,\nimplementation, and testing of software system. Through\nthe project, students will practise analysis of user’s needs,\nformulation of computing requirements to meet the user’s\nneeds, modelling and design of the computer systems\naccording to the requirements, evaluation of the design,\nefficient implementation of software components, system\nintegration, software version control, and rigorous testing.", + "preclusion" : "CS3201, CS3202", + "prerequisite" : "(CS2103/T or CS2113/T)" + }, + "CS5228" : { + "moduleCode" : "CS5228", + "title" : "Knowledge Discovery and Data Mining", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "This course introduces fundamental principles behind data mining and efficient techniques for mining large databases. It provides an overview of the algorithmic aspect of data mining: its efficiency (high-dimensional database indexing, OLAP, data reduction, compression techniques) and effectiveness (machine learning involving greedy search, branch and bound, stochastic search, parameter optimisation). Efficient techniques covered include association rules mining (Apriori algorithm, correlation search, constrained association rule discovery), classifier induction (decision trees, RainForest, SLIQ; Support vector machine; Naive Bayesian; classification based on association / visualisation), cluster analysis (k-means, k-mediods, DBSCAN, OPTICS, DENCLUE, STING, CLUSEQ, ROCK etc), and outliers/deviants detection (LOF, Distance-based outlier etc).", + "preclusion" : null, + "prerequisite" : "CS2102 and CS3243 and \n(EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS5346" : { + "moduleCode" : "CS5346", + "title" : "Information Visualisation", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to bring together individual pedagogies\nof design, information, and computation, for teaching the\nanalysis and representation of data for visualisation.\nStudents will learn the methodology of developing and\nevaluating an information visualisation solution, common\ninformation visualisation techniques (such as those for\ntopical, spatial, hierarchical, temporal, and relational data),\nand methods for scaling up interactive visualisation with big\ndata. After the module, students should be able to use the\nexisting visualisation tools for building useful, interactive,\ninformation visualisation to facilitate complex data\nanalytics, exploration, understanding, and pattern\ndiscovery.", + "preclusion" : null, + "prerequisite" : "(CS2040 or its equivalent) and CS2102 and CS3240 and \n(EE2012/A or ST1131/A or ST1232 or DSC2008 or ST2132 or ST2334)" + }, + "CS5224" : { + "moduleCode" : "CS5224", + "title" : "Cloud Computing", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module aims to provide an overview of the design, management and application of cloud computing. The topics include managing virtualization, cloud computing environments, cloud design patterns and use cases, data centre architectures and technologies, cloud services fulfillment and assurance, orchestration and automation of cloud resources, cloud capacity management, cloud economics, case studies.", + "preclusion" : null, + "prerequisite" : null + }, + "CS5223" : { + "moduleCode" : "CS5223", + "title" : "Distributed Systems", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The topic of Distributed Systems is now garnering increasing importance, especially with the advancement in technology of the Internet and WWW. The aim of this module is to provide students with basic concepts and principles of distributed operating systems, interprocess communications, distributed file systems, shared data, and the middleware approach. The module is taught in seminar style, and several case studies are included, e.g. CORBA. Topics: Introduction - Characteristics of Distributed Systems; Process Management Communication in Distributed Systems; Distributed Synchronisation; Distributed Real-time Systems; File Systems; Naming Security; Fault Tolerant Distributed Systems; Distributed Simulation; WWW as an application of Distributed System.", + "preclusion" : null, + "prerequisite" : "CS3211 Parallel and Concurrent Programming" + }, + "CS5344" : { + "moduleCode" : "CS5344", + "title" : "Big-Data Analytics Technology", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module analysis of data which can not fit in main memory and application of such analysis to web applications. The topics covered include: map-reduce as a tool for creating parallel algorithms that operate on very large amount of data, similarity search, data-streaming processing, search engine techonology, clustering of very large, high-dimensional datasets.", + "preclusion" : null, + "prerequisite" : "BT5110 (Data Management and Warehousing) or database related modules; programming experience (with data structures and algorithms) is required" + }, + "CS5222" : { + "moduleCode" : "CS5222", + "title" : "Advanced Computer Architecture", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "The aim of this module is to introduce the state-of-the-art architectural advances underlying the current generation of computing systems. A review of pipelined processor design and hierarchical memory design is followed by advanced topics including exploitation of instruction-level parallelism through dynamic instruction scheduling and speculation, exploiting thread-level parallelism through\nmultiprocessors, and optimizations for memory and storage subsystems. Throughout the module, particular emphasis will be placed on cost-performance-power-reliability trade-offs in designing the different architectural components.", + "preclusion" : null, + "prerequisite" : "CS3220 Computer Architecture or CS4223 Multi-core Architecture" + }, + "CS5340" : { + "moduleCode" : "CS5340", + "title" : "Uncertainty Modelling in AI", + "moduleCredit" : "4", + "semesters" : [ 1, 2 ], + "description" : "The module covers modelling methods that are suitable for reasoning with uncertainty. The main focus will be on probabilistic models including Bayesian networks and Markov networks. Topics include representing conditional independence, building graphical models, inference using graphical models and learning from data. Selected applications in various domains such as speech, vision, natural language processing, medical informatics, bioinformatics, data mining and others will be discussed.", + "preclusion" : null, + "prerequisite" : "CS3243 and \n(EE2012/A or ST2132 or ST2334 or ((MA2216 or ST2131) and (ST1131/A or ST1232 or DSC2008)))" + }, + "CS3281" : { + "moduleCode" : "CS3281", + "title" : "Thematic Systems Project I", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module is the first part of a two-part series on the development of large-scaled computer systems to solve real-world problems under specific themes such as healthcare, security and surveillance, tourism, etc. Students with complementary technical expertise will form project teams to work on real-world projects under the supervision of CS professors and industrial partners. This\nfirst part focuses on the analysis of the real-world problems, formulation of the computing requirements of the desired solution that meets the user’s needs, design of the computer systems according to the requirements, and evaluation of the design.", + "preclusion" : null, + "prerequisite" : "(CS2103 or its equivalent) and have passed at least one primary module in a CS focus area. Student selection process will be enforced." + }, + "CS3282" : { + "moduleCode" : "CS3282", + "title" : "Thematic Systems Project II", + "moduleCredit" : "4", + "semesters" : [ 2 ], + "description" : "This module is the second part of a two-part series on the development of large-scaled computer systems to solve real-world problems under specific themes such as healthcare, security and surveillance, tourism, etc. Students with complementary technical expertise will form project teams to work on real-world projects under the supervision of CS professors and industrial partners. This\nsecond part focuses on the development of algorithms required for the systems, implementation and testing of the algorithms and the systems, and evaluation of the systems according to the users’ requirements.", + "preclusion" : null, + "prerequisite" : "CS3281 and have passed at least two primary modules in a CS focus area. Student selection process will be enforced." + }, + "CP2201" : { + "moduleCode" : "CP2201", + "title" : "Journey of the Innovator", + "moduleCredit" : "2", + "semesters" : [ 2 ], + "description" : "Innovators practice the art of persuading people to accept changes in how they live—in work, leisure and social interaction. This module’s object is to introduce students to digital innovation, and to encourage them to embark on a personal journey of creativity and challenge. Inspirational innovators will be invited to present topics related to digital innovation, such as successful innovative projects of start-up teams and advanced development teams, innovative approaches such as Design Thinking, and opportunities for innovation, the vibrant intersection of energising technology trends and new markets. This module will be graded as “Completed Satisfactory” or “Completed Unsatisfactory”\n(CS/CU).", + "preclusion" : null, + "prerequisite" : null + }, + "IS4010" : { + "moduleCode" : "IS4010", + "title" : "Industry Internship Programme", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "This module enables students to apply the computing knowledge and skills that they have acquired in class to industry internships in companies/organizations. Students in industry internships will be jointly guided by supervisors from both the companies/organizations and the school Their progress on internship projects will be monitored during internship period, and their performance will be assessed through letter grades at the end of the internship. The internship duration will be 6 months, consisting of both a full-time and part-time component. Full-time internship attachment will last for 3 months during the NUS vacation period, and will continue on a part-time basis that will last for 3 months during the NUS study semester.", + "preclusion" : null, + "prerequisite" : "[IS2101 or CS2101] and [IS1105 or IS3101 or IS3103] and [IS2103 or CS2107 or (BT2101 and BT2102)]" + }, + "CP4101" : { + "moduleCode" : "CP4101", + "title" : "B.Comp. Dissertation", + "moduleCredit" : "12", + "semesters" : [ 1, 2 ], + "description" : "", + "preclusion" : "CS4101", + "prerequisite" : "Attain at least 70% of the MC requirement for the respective degree" + } +} diff --git a/src/main/resources/data/precludedmodules.json b/src/main/resources/data/precludedmodules.json new file mode 100644 index 00000000000..4771f7ead92 --- /dev/null +++ b/src/main/resources/data/precludedmodules.json @@ -0,0 +1,12 @@ +{ + "CS1101S": "CS1010, CS1010E, CS1010J, CS1010S, CS1010X", + "CS1231S" : "CS1231, MA1100", + "CS2030S" : "CS2030", + "CS2040S" : "CS1020, CS1020E, CS2020, CS2010, CS2040, CS2040C", + "CS2103T" : "CS2103T, CS2113, CS2113T, IS2101", + "CS2106" : "CG2271, EE4214", + "CS2101" : "CS2103, IS2101, ES2002, ES2007D, ES1601", + "MA1521" : "MA1102R, MA1312, MA1505, MA1507, MA2501, YSC1216", + "MA1101R" : "EG1401, EG1402, MA1101, MA1311, MA1506, MA1508, YSC2232", + "ST2334" : "ST1131, ST1131A, ST1232, ST2131, MA2216, CE2407, EC2231, EC2303, PR2103, DSC2008" +} diff --git a/src/main/resources/data/sciencemodules.json b/src/main/resources/data/sciencemodules.json new file mode 100644 index 00000000000..f4a006f1e1d --- /dev/null +++ b/src/main/resources/data/sciencemodules.json @@ -0,0 +1,78 @@ +{ + "modules" : [ { + "tagged" : [ "Chemistry" ], + "code" : "CM1121", + "title" : "Organic Chemistry 1", + "credits" : "4" + }, { + "tagged" : [ "Chemistry" ], + "code" : "CM1131", + "title" : "Physical Chemistry 1", + "credits" : "4" + }, { + "tagged" : [ "Chemistry" ], + "code" : "CM1417", + "title" : "Fundamentals of Chemistry", + "credits" : "4" + }, { + "tagged" : [ "Biology" ], + "code" : "LSM1102", + "title" : "Molecular Genetics", + "credits" : "4" + }, { + "tagged" : [ "Biology" ], + "code" : "LSM1105", + "title" : "Evolutionary Biology", + "credits" : "4" + }, { + "tagged" : [ "Biology" ], + "code" : "LSM1106", + "title" : "Molecular Cell Biology", + "credits" : "4" + }, { + "tagged" : [ "Biology" ], + "code" : "LSM1301", + "title" : "General Biology", + "credits" : "4" + }, { + "tagged" : [ "Biology" ], + "code" : "LSM1306", + "title" : "Forensic Science", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1141", + "title" : "Physics I", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1142", + "title" : "Physics II", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1143", + "title" : "Physics III", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1144", + "title" : "Physics IV", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1221", + "title" : "Fundamentals of Physics I", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1222", + "title" : "Fundamentals of Physics II", + "credits" : "4" + }, { + "tagged" : [ "Physics" ], + "code" : "PC1432", + "title" : "Physics IIE", + "credits" : "4" + }] +} diff --git a/src/main/resources/images/gradpad.png b/src/main/resources/images/gradpad.png new file mode 100644 index 00000000000..c9c74d291e8 Binary files /dev/null and b/src/main/resources/images/gradpad.png differ diff --git a/src/main/resources/images/logo.png b/src/main/resources/images/logo.png new file mode 100644 index 00000000000..5758852af9e Binary files /dev/null and b/src/main/resources/images/logo.png differ diff --git a/src/main/resources/view/CommandBox.fxml b/src/main/resources/view/CommandBox.fxml index 09f6d6fe9e4..db89f2f71f9 100644 --- a/src/main/resources/view/CommandBox.fxml +++ b/src/main/resources/view/CommandBox.fxml @@ -3,7 +3,6 @@ - - + + - diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 36e6b001cd8..d12b04a5f33 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -1,32 +1,32 @@ .background { - -fx-background-color: derive(#1d1d1d, 20%); - background-color: #383838; /* Used in the default.html file */ + -fx-background-color: derive(#192841, 20%); + background-color: #192841; /* Used in the default.html file */ } .label { -fx-font-size: 11pt; - -fx-font-family: "Segoe UI Semibold"; - -fx-text-fill: #555555; + -fx-font-family: Tahoma; + -fx-text-fill: #f5f5f5; -fx-opacity: 0.9; } .label-bright { -fx-font-size: 11pt; - -fx-font-family: "Segoe UI Semibold"; - -fx-text-fill: white; + -fx-font-family: Tahoma; + -fx-text-fill: #f5f5f5; -fx-opacity: 1; } .label-header { -fx-font-size: 32pt; - -fx-font-family: "Segoe UI Light"; - -fx-text-fill: white; + -fx-font-family: Tahoma; + -fx-text-fill: #f5f5f5; -fx-opacity: 1; } .text-field { -fx-font-size: 12pt; - -fx-font-family: "Segoe UI Semibold"; + -fx-font-family: Tahoma; } .tab-pane { @@ -40,9 +40,9 @@ } .table-view { - -fx-base: #1d1d1d; - -fx-control-inner-background: #1d1d1d; - -fx-background-color: #1d1d1d; + -fx-base: #192841; + -fx-control-inner-background: #192841; + -fx-background-color: #192841; -fx-table-cell-border-color: transparent; -fx-table-header-border-color: transparent; -fx-padding: 5; @@ -66,8 +66,8 @@ .table-view .column-header .label { -fx-font-size: 20pt; - -fx-font-family: "Segoe UI Light"; - -fx-text-fill: white; + -fx-font-family: Tahoma; + -fx-text-fill: #f5f5f5; -fx-alignment: center-left; -fx-opacity: 1; } @@ -77,20 +77,20 @@ } .split-pane:horizontal .split-pane-divider { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#192841, 20%); -fx-border-color: transparent transparent transparent #4d4d4d; } .split-pane { -fx-border-radius: 1; -fx-border-width: 1; - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#192841, 20%); } .list-view { -fx-background-insets: 0; -fx-padding: 0; - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#192841, 20%); } .list-cell { @@ -100,106 +100,117 @@ } .list-cell:filled:even { - -fx-background-color: #3c3e3f; + -fx-background-color: #192841; } .list-cell:filled:odd { - -fx-background-color: #515658; -} - -.list-cell:filled:selected { - -fx-background-color: #424d5f; -} - -.list-cell:filled:selected #cardPane { - -fx-border-color: #3e7b91; - -fx-border-width: 1; -} - -.list-cell .label { - -fx-text-fill: white; + -fx-background-color: derive(#192841, 10%); } .cell_big_label { - -fx-font-family: "Segoe UI Semibold"; + -fx-font-family: Tahoma; -fx-font-size: 16px; - -fx-text-fill: #010504; + -fx-text-fill: #f5f5f5; +} + +.cell_medium_label { + -fx-font-family: Tahoma; + -fx-font-size: 14px; + -fx-text-fill: derive(#ef7c00, 80%); } .cell_small_label { - -fx-font-family: "Segoe UI"; - -fx-font-size: 13px; - -fx-text-fill: #010504; + -fx-font-family: Tahoma; + -fx-font-size: 14px; + -fx-text-fill: #f5f5f5; } .stack-pane { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#192841, 20%); } .pane-with-border { - -fx-background-color: derive(#1d1d1d, 20%); - -fx-border-color: derive(#1d1d1d, 10%); - -fx-border-top-width: 1px; + -fx-background-color: #192841; + -fx-border-color: #192841 derive(#192841, 10%) #192841 derive(#192841, 10%); + -fx-border-top-width: 0.3px; +} + +.pane-without-border { + -fx-background-color: transparent; } .status-bar { - -fx-background-color: derive(#1d1d1d, 30%); + -fx-background-color: #192841; +} + +.intro-display { + -fx-background-color: transparent; + -fx-font-family: Courier; + -fx-font-size: 11px; + -fx-text-fill: derive(#ef7c00, 80%); +} + +.intro-display-enter { + -fx-background-color: transparent; + -fx-font-family: Courier; + -fx-font-size: 11px; + -fx-text-fill: #f5f5f5; } .result-display { -fx-background-color: transparent; - -fx-font-family: "Segoe UI Light"; - -fx-font-size: 13pt; - -fx-text-fill: white; + -fx-font-family: Tahoma; + -fx-font-size: 16px; + -fx-text-fill: #f5f5f5; } .result-display .label { - -fx-text-fill: black !important; + -fx-text-fill: #f5f5f5 !important; } .status-bar .label { - -fx-font-family: "Segoe UI Light"; - -fx-text-fill: white; - -fx-padding: 4px; - -fx-pref-height: 30px; + -fx-font-family: Tahoma; + -fx-text-fill: derive(#ef7c00, 10%); + -fx-font-size: 9pt; + -fx-padding: 7px; } .status-bar-with-border { - -fx-background-color: derive(#1d1d1d, 30%); - -fx-border-color: derive(#1d1d1d, 25%); - -fx-border-width: 1px; + -fx-background-color: derive(#192841, 30%); + -fx-border-color: derive(#192841, 25%); + -fx-border-width: 10px; } .status-bar-with-border .label { - -fx-text-fill: white; + -fx-text-fill: #f5f5f5; } .grid-pane { - -fx-background-color: derive(#1d1d1d, 30%); - -fx-border-color: derive(#1d1d1d, 30%); + -fx-background-color: derive(#192841, 30%); + -fx-border-color: derive(#192841, 30%); -fx-border-width: 1px; } .grid-pane .stack-pane { - -fx-background-color: derive(#1d1d1d, 30%); + -fx-background-color: derive(#192841, 30%); } .context-menu { - -fx-background-color: derive(#1d1d1d, 50%); + -fx-background-color: derive(#192841, 50%); } .context-menu .label { - -fx-text-fill: white; + -fx-text-fill: #f5f5f5; } .menu-bar { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#192841, 20%); } .menu-bar .label { -fx-font-size: 14pt; - -fx-font-family: "Segoe UI Light"; - -fx-text-fill: white; + -fx-font-family: Tahoma; + -fx-text-fill: #f5f5f5; -fx-opacity: 0.9; } @@ -217,8 +228,8 @@ -fx-border-color: #e2e2e2; -fx-border-width: 2; -fx-background-radius: 0; - -fx-background-color: #1d1d1d; - -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif; + -fx-background-color: #192841; + -fx-font-family: Tahoma; -fx-font-size: 11pt; -fx-text-fill: #d8d8d8; -fx-background-insets: 0 0 0 0, 0, 1, 2; @@ -230,7 +241,7 @@ .button:pressed, .button:default:hover:pressed { -fx-background-color: white; - -fx-text-fill: #1d1d1d; + -fx-text-fill: #192841; } .button:focused { @@ -243,8 +254,8 @@ .button:disabled, .button:default:disabled { -fx-opacity: 0.4; - -fx-background-color: #1d1d1d; - -fx-text-fill: white; + -fx-background-color: #192841; + -fx-text-fill: #f5f5f5; } .button:default { @@ -257,37 +268,37 @@ } .dialog-pane { - -fx-background-color: #1d1d1d; + -fx-background-color: #192841; } .dialog-pane > *.button-bar > *.container { - -fx-background-color: #1d1d1d; + -fx-background-color: #192841; } .dialog-pane > *.label.content { -fx-font-size: 14px; -fx-font-weight: bold; - -fx-text-fill: white; + -fx-text-fill: #f5f5f5; } .dialog-pane:header *.header-panel { - -fx-background-color: derive(#1d1d1d, 25%); + -fx-background-color: derive(#192841, 25%); } .dialog-pane:header *.header-panel *.label { -fx-font-size: 18px; -fx-font-style: italic; -fx-fill: white; - -fx-text-fill: white; + -fx-text-fill: #f5f5f5; } .scroll-bar { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: #192841; } .scroll-bar .thumb { - -fx-background-color: derive(#1d1d1d, 50%); - -fx-background-insets: 3; + -fx-background-color: derive(#ef7c00, 10%); + -fx-background-insets: 4; } .scroll-bar .increment-button, .scroll-bar .decrement-button { @@ -318,22 +329,18 @@ } #commandTextField { - -fx-background-color: transparent #383838 transparent #383838; - -fx-background-insets: 0; - -fx-border-color: #383838 #383838 #ffffff #383838; - -fx-border-insets: 0; -fx-border-width: 1; - -fx-font-family: "Segoe UI Light"; - -fx-font-size: 13pt; - -fx-text-fill: white; + -fx-font-family: Tahoma; + -fx-font-size: 11pt; + -fx-text-fill: #555555; } -#filterField, #personListPanel, #personWebpage { - -fx-effect: innershadow(gaussian, black, 10, 0, 0, 0); +#filterField, #moduleListPanel, #personWebpage { + -fx-effect: innershadow(gaussian, white, 10, 0, 0, 0); } #resultDisplay .content { - -fx-background-color: transparent, #383838, transparent, #383838; + -fx-background-color: transparent, #192841, #ffffff, #192841; -fx-background-radius: 0; } @@ -343,10 +350,10 @@ } #tags .label { - -fx-text-fill: white; + -fx-text-fill: #f5f5f5; -fx-background-color: #3e7b91; -fx-padding: 1 3 1 3; -fx-border-radius: 2; -fx-background-radius: 2; - -fx-font-size: 11; + -fx-font-size: 13px; } diff --git a/src/main/resources/view/Extensions.css b/src/main/resources/view/Extensions.css index bfe82a85964..713816da7e5 100644 --- a/src/main/resources/view/Extensions.css +++ b/src/main/resources/view/Extensions.css @@ -5,7 +5,7 @@ .list-cell:empty { /* Empty cells will not have alternating colours */ - -fx-background: #383838; + -fx-background: #192841; } .tag-selector { diff --git a/src/main/resources/view/HelpWindow.fxml b/src/main/resources/view/HelpWindow.fxml deleted file mode 100644 index fa0fb54d9f4..00000000000 --- a/src/main/resources/view/HelpWindow.fxml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/view/IntroDisplay.fxml b/src/main/resources/view/IntroDisplay.fxml new file mode 100644 index 00000000000..0090a6c776e --- /dev/null +++ b/src/main/resources/view/IntroDisplay.fxml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index a431648f6c0..7ab644c4cc1 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -3,18 +3,15 @@ - - - - + + - + - + @@ -23,35 +20,21 @@ - - - - - - - - - + + + + + + - - - - - + + + - - - - - - - - - - - - + + + + diff --git a/src/main/resources/view/ModuleListCard.fxml b/src/main/resources/view/ModuleListCard.fxml new file mode 100644 index 00000000000..bef249efc2b --- /dev/null +++ b/src/main/resources/view/ModuleListCard.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/ModuleListPanel.fxml similarity index 77% rename from src/main/resources/view/PersonListPanel.fxml rename to src/main/resources/view/ModuleListPanel.fxml index 8836d323cc5..88180215379 100644 --- a/src/main/resources/view/PersonListPanel.fxml +++ b/src/main/resources/view/ModuleListPanel.fxml @@ -4,5 +4,5 @@ - + diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml deleted file mode 100644 index f08ea32ad55..00000000000 --- a/src/main/resources/view/PersonListCard.fxml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/view/ResultDisplay.fxml b/src/main/resources/view/ResultDisplay.fxml index 58d5ad3dc56..5b13c722573 100644 --- a/src/main/resources/view/ResultDisplay.fxml +++ b/src/main/resources/view/ResultDisplay.fxml @@ -3,7 +3,6 @@ - -