By: Team W09-1      Since: Feb 2019      Licence: MIT

1. Introduction

Welcome to UltiStudent! UltiStudent is a student application that effectively tackles the problem of having too many applications to manage their school life. To improve the quality of student life in computing, UltiStudent provides a centralised platform for them to manage their homework, cumulative average point and notes. UltiStudent is a desktop-based application intended for students.

This Developer Guide is written for anyone who wishes to contribute to our project. In here, you will find information to help you to set up our project and information to help you understand the architecture behind UltiStudent and how our key features work.

If you would like to help to improve this project by contributing, do contact us for more information!

1.1. Callouts & Symbols

Before proceeding, do refer to the below callout signs that will be used across this document. Familiarising yourself with them will definitely prove to be helpful.

This callout shares note-worthy information with you. Do read them for a better understanding of the document.
This callout shares helpful tips with you. Not to worry, tips can be good to know but are not vital. Information found here are additional and can prove to be handy for you.
This callout indicates that there is worth being cautioned of. You are encouraged to the read information in here. If you are not careful, you may encounter problems.

2. Setting up

Do follow the instructions in order to set up our project on your device.

2.1. Prerequisites

  1. JDK 9 or later

    JDK 10 on Windows will fail to run tests in headless mode due to a JavaFX bug. Windows developers are highly recommended to use JDK 9.
  2. IntelliJ IDE

    IntelliJ by default has Gradle and JavaFx plugins installed.
    Do not disable them. If you have disabled them, go to File > Settings > Plugins to re-enable them.

2.2. Setting up the project in your computer

  1. Fork this repo, and clone the fork to your computer

  2. Open IntelliJ (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first)

  3. Set up the correct JDK version for Gradle

    1. Click Configure > Project Defaults > Project Structure

    2. Click New…​ and find the directory of the JDK

  4. Click Import Project

  5. Locate the build.gradle file and select it. Click OK

  6. Click Open as Project

  7. Click OK to accept the default settings

  8. Open a console and run the command gradlew processResources (Mac/Linux: ./gradlew processResources). It should finish with the BUILD SUCCESSFUL message.
    This will generate all resources required by the application and tests.

  9. Open MainWindow.java and check for any code errors

    1. Due to an ongoing issue with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully

    2. To resolve this, place your cursor over any of the code section highlighted in red. Press ALT+ENTER, and select Add '--add-modules=…​' to module compiler options for each error

  10. Repeat this for the test folder as well (e.g. check HelpWindowTest.java for code errors, and if so, resolve it the same way)

2.3. Verifying the setup

  1. Run the seedu.ultistudent.MainApp and try a few commands

  2. Run the tests to ensure they all pass.

2.4. Configurations to do before writing code

2.4.1. Configuring the coding style

This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,

  1. Go to File > Settings…​ (Windows/Linux), or IntelliJ IDEA > Preferences…​ (macOS)

  2. Select Editor > Code Style > Java

  3. Click on the Imports tab to set the order

    • For Class count to use import with '*' and Names count to use static import with '*': Set to 999 to prevent IntelliJ from contracting the import statements

    • For Import Layout: The order is import static all other imports, import java.*, import javax.*, import org.*, import com.*, import all other imports. Add a <blank line> between each import

Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.

2.4.2. Setting up CI

Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.

After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).

Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork.

Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).

Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based)

2.4.3. Getting started with coding

When you are ready to start coding,

  1. Get some sense of the overall design by reading Section 3.1, “Architecture”.

  2. Take a look at [GetStartedProgramming].

3. Design

3.1. Architecture

Architecture
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .pptx files used to create diagrams in this document can be found in the diagrams folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose Save as picture.

Main has only one class called MainApp. 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 method where necessary.

Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

Each of the four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

LogicClassDiagram UltiStudent
Figure 2. Class Diagram of the Logic Component

How the architecture components interact with each other

The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

SDforDeleteHomework
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

3.2. UI component

UltiStudentUiClassDiagram updated
Figure 4. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, PersonListPanel, StatusBarFooter, BrowserPanel 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 is specified in MainWindow.fxml

The UI component,

  • Executes user commands using the Logic component.

  • Listens for changes to Model data so that the UI can be updated with the modified data.

3.3. Logic component

UltiStudentLogicClassDiagram
Figure 5. Structure of the Logic Component

API : Logic.java

  1. Logic uses the UltiStudentParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the Model (e.g. adding a homework).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteHomeworkSdForLogic updated
Figure 6. Interactions Inside the Logic Component for the delete 1 Command

3.4. Model component

ModelComponentClass
Figure 7. Structure of the Model Component

API : Model.java

The Model,

  • stores a UserPref object that represents the user’s preferences.

  • stores the UltiStudent data.

  • exposes an unmodifiable ObservableList<Homework> 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.

3.5. Storage component

UltiStudentStorageClassDiagram
Figure 8. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the UltiStudent data in json format and read it back.

3.6. Common classes

Classes used by multiple components are in the seedu.ultistudent.commons package.

4. Implementation

This section describes some noteworthy details on how certain features are implemented.

4.1. Adding a homework: add-hw

The add homework feature is a core feature to the Homework Manager of UltiStudent. Which allows the users to create a homework object in UltiStudent.

4.1.1. Overview

The add homework add-hw mechanism is facilitated by AddHomeworkCommand and AddHomeworkCommandParser. It takes in the following input from the user: ModuleCode, HomeworkName and Date, which will construct individual objects that construct a Homework object.

The AddHomeworkCommandParser implements Parser with the following operation:

  • AddHomeworkCommandParser#parse() - This operation will take in a String input from the user that will create individual objects based on the prefixes 'mc/', 'hw/' and 'd/'. The String value after the individual prefixes will create the respective object: 'mc/' for ModuleCode, 'hw/' for HomeworkName and 'd/' for Date. A validation check will be imposed upon the creation of each object. Any checks that fails the validation would prompt the user on the failed component. For example:

    • ModuleCode would use ParserUtil#parseHomeworkModuleCode() to ensure that user has input 2 letters followed by 4 digits with an option to include a optional letter after the 4 digits.

    • HomeworkName would use ParserUtil#parseHomeworkName() to ensure that homework name is not a null.

    • Date would use ParserUtil#parseDate() to ensure that user has entered a date that is either a present or future date.

  • After validation checks are completed with no errors, a Homework object is then constructed with ModuleCode, HomeworkName and Date as the parameters

  • AddHomeworkCommandParser would then return a AddHomeworkCommand object with the Homework as the parameter

Take a look at the code snippet of AddHomeworkCommandParser below for an illustration:

AddHomeworkCommandParser snippet
Figure 9. Code snippet for AddHomeworkCommandParser

4.1.2. Example

Given below is an example usage scenario of how add-hw mechanism behaves at each step.

Step 1: The user executes add-hw mc/CS1101S hw/Tutorial 1 d/01/05/2019 to add a CS1101S Tutorial 1 homework with the deadline on 1st May 2019.

Step 2: LogicManager would use UltiStudentParser#parse() to parse the input from the user.

Step 3: UltiStudentParser would determine which command is being used and creates the respective parser. In this case, AddHomeworkCommandParser is being created and the user’s input would be pass in as a parameter.

Step 4: AddHomeworkCommandParser would do a validation check on the user’s input before creating and returning a AddHomeworkCommand object with Homework as the parameter.

Step 5: LogicManager would use AddHomeWorkCommand#execute() to add the ModuleCode and Homework into the Model which is handled by ModelManager

Step 6: AddHomeworkCommand would return a CommandResult to the LogicManager which would then be return back to the user.

The image below illustrates the scenario of when the user executes add-hw mc/CS1101S hw/Tutorial 1 d/01/05/2019:

AddHomeworkSequentialDiagram
Figure 10. Sequential Diagram for add-hw

4.2. Delete homework feature

This feature allows the user to delete a homework entry from the homework manager through its index.

The delete homework feature is facilitated by the DeleteHomeworkCommandParser and the DeleteHomeworkCommand.

The delete command is part of the logic component of our application. It interacts with the model and the storage components of our application.

4.2.1. Overview

The DeleteHomeworkCommandParser implements Parser with the following operation:

  • DeleteHomeworkCommandParser#parse() - This operation will take in a int input from the user which will delete the homework entry at the index which has entered. Any invalid format of the command will be prompted by the command parser.

4.2.2. Current Implementation

The delete homework feature is executed by the DeleteHomeworkCommand. Currently, the deletion of any homework entry is done based on the INDEX of the homework entry.

During the design of our delete function, we considered between two alternatives.

Design Consideration Pros and Cons

Deletion by Index (Current Choice)

Pros: Since each homework has a unique index, any deletion by the index is less prone to bugs and easier to implement.

Cons: User will have to scroll for the homework entry and look for its index which can be inconvenient

Deletion by Homework Name

Pros: It may be more intuitive for users to delete a homework through the name of the homework.

Cons: Homework for different modules can have different names. For example, two different homework entries for two different modules can be called 'Tutorial 1'.

We have decided to opt for the first option primarily because it reduces the number of potential bugs and the complexities involved when taking into account the different cases upon using deletion by homework name.

4.3. Edit homework feature

This feature allows the user to edit any attribute of the homework entries. This is a core feature because the user may have to update deadline or make corrections to mistakes, such as typographical errors, when adding a homework entry. There are a total of three attributes for each entry, the module code, the homework name and the deadline. The user can edit at least one and up to three attributes.

The edit homework feature is facilitated by the EditHomeworkCommandParser and the EditHomeworkCommand.

The edit command is part of the logic component of our application. It interacts with the model component of our software architecture.

4.3.1. Overview

The EditHomeworkCommandParser implements Parser with the following operation:

  • EditHomeworkCommandParser#parse() - This operation will take in an int input and one to three String input(s) from the user that will alter the attributes of current homework entries based on the prefixes 'mc/', 'hw/' and 'd/'. The String value after the individual prefixes will alter the respective attribute it corresponds to: 'mc/' for ModuleCode,'hw/' for HomeworkName and 'd/' for Date. A validation check will be imposed upon editing of each object. Any checks that fails the validation would prompt the user on the failed component.

4.3.2. Current Implementation

Here is an example of a step-by-step process on how the edit command alters an attribute of the homework entry. For each step, you may follow the activity diagram at the end of this section to better understand the flow of events within UltiStudent when an edit-hw command is inputted.

Step 1. The user launches the application and opens the homework manager. There is a list of existing homework entries in the homework manager.

Step 2. The user then wishes to alter the homework deadline of the third entry in the homework list to 10 May 2019. He then types edit-hw d/10/05/2019 into the Command Line Interface (CLI) and executes it.

Step 3. The UltiStudentParser (refer to logic) then reads in these attributes that have been inputted and proceeds to alter the attributes of the homework entry in the given index. Each attribute will be validated.

Step 4. The UltiStudentParser then creates a new EditHomeworkCommand based on the input of the user. When the EditHomeworkCommand is executed, it interacts with the Model architecture by calling the setHomework method. The setHomework method replaces the current homework entry with the a new homework entry containing all the desired attributes. The homework entry is now updated.

Step 5. If the module code for any homework entry has been edited to a module code that is not in the module code list, the EditHomeworkCommand will add the new module code into the module code list. The updated module code list will be displayed on our User Interface.

edit hw activity diagram
Figure 11. Activity diagram for edit-hw

In designing the edit homework feature, we considered if we should use an alternative data structure to update the list of module codes. We considered using a hash map to map the module code to the number of homework with the modules to check if the module code list has to be updated for each edit.

Design Consideration Pros and Cons

Update ModuleList by iteration (Current Choice)

Pros: Protects the abstraction layers and modularity by restricting the usage to the existing data structures already present in our code.

Cons: Less efficient in terms of time and actual time taken can be long when number of entries is large.

Update ModuleList using help from other data structures.

Pros: Faster expected performance.

Cons: Introducing a new data structure can disrupt the existing abstractions of our code.

To sum up our justification of our choice of design, we decided to opt for the first option because we prioritised the existing design abstractions in our code over the efficiency of our code.

4.4. Find module feature

This feature allows the user to only display homework belonging to one or more module codes which is user has specified. The find module feature is exceptionally useful to shorten the displayed list of homework.

The find module feature is facilitated by the FindModuleCommandParser and the FindModuleCommand. It interacts with the model component of our architecture to retrieve the list homework.

4.4.1. Overview

The FindModuleCommandParser implements Parser with the following operation:

  • FindModuleCommandParser#parse() - This operation will take in at least one String input from the user and display any of the homework entries with matches any of list of [KEYWORDS] that the user has inputted. Each keyword is separated by a white space. Any homework entry that matches with the list of keywords will be displayed on the homework list.

4.4.2. Current Implementation

The find module feature is facilitated by the FindModuleCommand.

Here is a sequence of steps on how the find module feature works. We will use an example here to help you understand the flow of events. In the steps below, we will make references to the diagram at the end of the section to help you visualise the sequence of events better.

Step 1. The user first launches the application and enters the homework manager. There are already existing homework entries within the homework list.

Step 2. Currently, there are a total of twelve homework entries belonging to four modules. (Do note that this is an arbitrary state of the storage in the homework manager and is meant to serve as an example.) Now the user inputs find mod CS1101S. Referring to the diagram below, UltiStudentCommandParser parses the command find-mod together with the list of keywords.

Step 3. The FindModuleParser then creates a FindModuleCommand and then returns it to the LogicManager, which are illustrated by the blue arrows pointing from the command parsers back to the LogicManger.

Step 4. Now, the Logic Manager then executes this command. When the find command is executed, it called the method updateFilteredList, which then returns a list of homework that has the module codes which matches any of the key words inputted back to the Logic Manager as indicated by the purple arrows pointing back to the Logic Manager’s blue block.

find mod sequence diagram
Figure 12. Sequence diagram for find-mod

4.5. Adding a note : add-note

The add homework feature is a core feature to the Homework Manager of UltiStudent. Which allows the users to create a homework object in UltiStudent.

4.5.1. Overview

The add note add-note mechanism is facilitated by AddNoteCommand and AddNoteCommandParser. It takes in the following input from the user: ModuleCode and NoteName which will construct individual objects that construct a Note object.

The AddNoteCommandParser implements Parser with the following operation:

  • AddNoteCommandParser#parse() - This operation will take in a String input from the user that will create individual objects based on the prefixes 'mc/' and 'n/'. The String value after the individual prefixes will create the respective object: 'mc/' for ModuleCode and 'n/' for NoteName. A validation check will be imposed upon the creation of each object. Any checks that fails the validation would prompt the user on the failed component.

For example:

  • ModuleCode would use ParserUtil#parseNoteModuleCode to ensure that user has input 2 letters followed by 4 digits with an option to include a optional letter after the 4 digits.

  • NoteName would use ParserUtil#parseNoteName to ensure that note name is not a null.

    • After validation checks are completed with no errors, a Note object is then constructed with ModuleCode and NoteName.

    • AddNoteCommandParser would then return a AddNoteCommand object with the Note as the parameter

4.5.2. Example

Given below is an example usage scenario of how add-note mechanism behaves at each step.

Step 1: The user executes `add-note mc/CS2103T n/Week 1 Lecture to add a note for CS2103T Week 1 Lecture.

Step 2: LogicManager would use UltiStudentParser#parse() to parse the input from the user.

Step 3: UltiStudentParser would determine which command is being used and creates the respective parser. In this case, AddNoteCommandParser is being created and the user’s input would be pass in as a parameter.

Step 4: AddNoteCommandParser would do a validation check on the user’s input before creating and returning a AddNoteCommand object with Note as the parameter.

Step 5: LogicManager would use AddNoteCommand#execute() to add the ModuleCode and Note into the Model which is handled by ModelManager

Step 6: AddNoteCommand would return a CommandResult to the LogicManager which would then be return back to the user.

The image below illustrates the scenario of when the user executes add-hw mc/CS1101S hw/Tutorial 1 d/01/05/2019:

AddNoteSequentialDiagram
Figure 13. Sequential Diagram for add-note

4.6. Deleting a note : delete-note

This feature allows the user to delete a note from the homework manager through its index.

The delete note feature is facilitated by the DeleteNoteCommandParser and the DeleteNoteCommand.

The delete command is part of the logic component of our application. It interacts with the model and the storage components of our application.

4.6.1. Overview

The DeleteNoteCommandParser implements Parser with the following operation:

  • DeleteNoteCommandParser#parse() - This operation will take in a int input from the user which will delete the note entry at the index which has entered. Any invalid format of the command will be prompted by the command parser.

4.6.2. Current Implementation

The delete note feature is executed by the DeleteNoteCommand. Currently, the deletion of any note entry is done based on the INDEX of the note entry.

During the design of our delete function, we considered between two alternatives.

Description of Implementation Pros and Cons

Deletion by Index (Current Choice)

Pros: Since each note has a unique index within each list, deleting a note by its index is less prone to bugs and will be easier to implement.

Cons: User will need to scroll for the entry and look for its index which can be inconvenient.

Deletion by Homework Name

Pros: It may be more intuitive for users to delete a note through its note name.

Cons: Notes for different modules can have similar names. For example, two different note entries for two different modules can be called 'Week 7 Lecture'. This may cause it to be more error-prone.

We have decided to opt for the first option primarily because it reduces the number of potential bugs and the complexities involved when taking into account the different cases upon using deletion by note name.

4.7. Editing and Saving a note : edit-note save-note

These two feature allows the user to edit existing note and save them after editing.

4.7.1. Overview

The edit-note command helps the user to open the selected notes to allow the user to start editing its content by displaying all the content on the NotesManagerMainPanel which is a text field. It requires the need of the save-note command to help save the user’s edits

Below is an activity diagram of how the users use edit-note and save-note to facilitate adding contents to their existing notes:

Edit&SaveNoteActivityDiagram
Figure 14. Activity Diagram for edit-note and save-note

Step 1: User will key in edit-note INDEX on the command line

Step 2: System will do a validation check to see if INDEX of note exist in the list of notes in the Model. If note does not exist, it will throw a ParserException to the user. Else note will be opened and proceed to step 3.

Step 3: Once it is opened, NotesManagerMainPanel will be enabled, allowing the user to start typing their notes in the text field.

Step 4: When the user is done editing, he/she can use save-note in the command line to save the edited content to the opened note.

Step 5: Upon successful save, NotesManagerMainPanel will be disabled and user will not be able to type anything on NotesManagerMainPanel

4.7.2. Design Considerations

Options

Pro

Cons

1. Users to type their content on the command line

- Easy implementation
- Single source of input
- No need to handle special key press

- Not user friendly
- Non-editable visual (textfield)
- Special commands for NotesManager to take in input from Command Line as note’s content
- A need to convert from Command Line mode to Text Input mode

2. Users to type their content on the NotesManagerMainPanel

- User friendly
- A separate source of input

- Two sources of input, Command Line and TextField
- Harder implementation, requires handling of special key press

Option 2 is being selected and implemented as we focus on the users convenience and the ability to edit their notes easily. Separation of command line and notes text field would reduce the number of commands the user has to remember and there will be lesser confusion of command line mode or text input mode.

4.8. Editing a Cap Entry : edit-cap

This feature allows the user to edit a cap entry from the cap entry list. Users can do so either via: the cap entry’s index with the edit-cap command or the cap entry’s module code with the edit-cap-mc

4.8.1. Current Implementation

The edit-cap command is facilitated by the Logic and Model components of the application, UltiStudent.

The sequence diagram below shows how the editing of cap entries work when the user enters edit-cap

EditCapManagerSequenceDiagram
Figure 15. Sequence Diagram for edit-cap

The sequence diagram for the "Update Module Semester" reference frame above can be seen below.

EditCapManagerSequenceDiagram2
Figure 16. Reference Frame for Update Module Semester

Given below is an example usage scenario of how edit-cap behaves at each step.

Step 1: The user launches the application and opens the CAP Manager.

Step 2: There are already existing CAP entries. The user now executes edit-cap 2 g/A sem/Y2S2 to edit the cap entry in the 2nd index with grade A and moduleSemester of Y2S2.

Step 3: Upon executing this command, the EditCapCommandParser will take in all the arguments inputted and create a EditCapCommand object. This object is then returned to the Logic Manager which will then execute the EditCommand

Step 4: When executing the EditCapCommand this alters the attributes of the CAP Entry in the UniqueCapEntryList object of UltiStudent by setCapEntry(a,b) method, where a is the cap entry to edit, and b is the edited cap entry. In doing so, this will call the method of updateCapForDelete(a) and updateCapForAdd(b), which will update the CAP score.

Step 5: Next, the UniqueModuleSemesterList will be updated. This is done by the updateModuleSemesterList(x,y) where x is the moduleSemesterOfCapEntry to edit, while y is the moduleSemesterOfEditedCapEntry.

Step 6: If moduleSemesterOfCapEntry is different from moduleSemesterOfEditedCapEntry, the model will check if it contains moduleSemesterOfEditedCapEntry. If it does not, moduleSemesterOfEditedCapEntry will be added to the UniqueModuleSemesterList.

Step 7: On the other hand, if the model does not have any cap entries with the same semesters as moduleSemesterOfCapEntry after editing the cap entries, which is reflected if hasCapEntriesWithSameSemester is false. The moduleSemesterOfCapEntryToEdit will be deleted to the UniqueModuleSemesterList.

4.8.2. Design Considerations

Aspect: How to store the Cap Score.
  • Alternative 1 (current choice): Store the cap score as a static variable in CapEntry class.

    • Pros: Easy to implement.

    • Cons: Since a static variable belongs to the CapEntry class, there may be unintended side effects when we use commands to modify the UniqueCapEntryList.

  • Alternative 2: Store the cap score as a separate class that is then store in UltiStudent.

    • Pros: Each versioned UltiStudent will have their own cap score.

    • Cons: Will use more memory and is harder to implement.

Aspect: How to assign score for module grade.
  • Alternative 1 (current choice): Use a Hash Map to get the Store the cap score as a static variable in CapEntry class.

    • Pros: Lower time complexity O(1) and cleaner code.

    • Cons: Larger memory occupation.

  • Alternative 2: Use switch cases to find and allocate score to grade.

    • Pros: Easier readability.

    • Cons: Slower time complexity, worst case of O(N).

4.9. Deleting a Cap Entry : delete-cap

This feature allows the user to delete a cap entry from the cap entry list. Users can do so either via: the cap entry’s index with the delete-cap command or the cap entry’s module code with the delete-cap INDEX

4.9.1. Current Implementation

The delete-cap command is facilitated by the Logic and Model components of the application, UltiStudent.

The activity diagram below shows how the deleting of cap entries work when the user enters delete-cap.

DeleteCapManagerActivityDiagram
Figure 17. Activity Diagram for delete-cap

Given below is an example usage scenario of how delete-cap behaves at each step.

Step 1: The user executes delete-cap 2 to delete the cap entry in the 2nd index.

Step 2: Upon executing this command, the DeleteCapCommandParser parses the arguments and checks if the arguments are valid. If not valid, the command throws an exception and terminates.

Step 3: If the argument is valid, the command checks if the CapEntry exists in the CAP Manager. If it does, the entry is deleted. The UniqueCapEntryList is then updated and the CAP score is updated as well.

Step 4: Check if after deleting the target CapEntry the UniqueCapEntryList still has a CapEntry of the same semester. If there is, the module semester will be deleted from the UniqueModuleSemesterList. Then the UniqueModuleSemesterList will be updated.

4.10. Logging

We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 4.11, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

4.11. Configuration

Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).

5. Documentation

We use asciidoc for writing documentation.

We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting.

5.1. Editing Documentation

See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits. Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.

5.2. Publishing Documentation

See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.

5.3. Converting Documentation to PDF format

We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.

Here are the steps to convert the project documentation files to PDF format.

  1. Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the docs/ directory to HTML format.

  2. Go to your generated HTML files in the build/docs folder, right click on them and select Open withGoogle Chrome.

  3. Within Chrome, click on the Print option in Chrome’s menu.

  4. Set the destination to Save as PDF, then click Save to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.

chrome save as pdf
Figure 18. Saving documentation as PDF files in Chrome

5.4. Site-wide Documentation Settings

The build.gradle file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.

Attributes left unset in the build.gradle file will use their default value, if any.
Table 1. List of site-wide attributes
Attribute name Description Default value

site-name

The name of the website. If set, the name will be displayed near the top of the page.

not set

site-githuburl

URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar.

not set

site-seedu

Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items.

not set

5.5. Per-file Documentation Settings

Each .adoc file may also specify some file-specific asciidoc attributes which affects how the file is rendered.

Asciidoctor’s built-in attributes may be specified and used as well.

Attributes left unset in .adoc files will use their default value, if any.
Table 2. List of per-file attributes, excluding Asciidoctor’s built-in attributes
Attribute name Description Default value

site-section

Site section that the document belongs to. This will cause the associated item in the navigation bar to be highlighted. One of: UserGuide, DeveloperGuide, LearningOutcomes*, AboutUs, ContactUs

* Official SE-EDU projects only

not set

no-site-header

Set this attribute to remove the site navigation bar.

not set

5.6. Site Template

The files in docs/stylesheets are the CSS stylesheets of the site. You can modify them to change some properties of the site’s design.

The files in docs/templates controls the rendering of .adoc files into HTML5. These template files are written in a mixture of Ruby and Slim.

Modifying the template files in docs/templates requires some knowledge and experience with Ruby and Asciidoctor’s API. You should only modify them if you need greater control over the site’s layout than what stylesheets can provide. The SE-EDU team does not provide support for modified template files.

6. Testing

6.1. Running Tests

There are three ways to run tests.

The most reliable way to run tests is the 3rd one. The first two methods might fail some GUI tests due to platform/resolution-specific idiosyncrasies.

Method 1: Using IntelliJ JUnit test runner

  • To run all tests, right-click on the src/test/java folder and choose Run 'All Tests'

  • To run a subset of tests, you can right-click on a test package, test class, or a test and choose Run 'ABC'

Method 2: Using Gradle

  • Open a console and run the command gradlew clean allTests (Mac/Linux: ./gradlew clean allTests)

See UsingGradle.adoc for more info on how to run tests using Gradle.

Method 3: Using Gradle (headless)

Thanks to the TestFX library we use, our GUI tests can be run in the headless mode. In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.

To run tests in headless mode, open a console and run the command gradlew clean headless allTests (Mac/Linux: ./gradlew clean headless allTests)

6.2. Types of tests

We have two types of tests:

  1. GUI Tests - These are tests involving the GUI. They include,

    1. System Tests that test the entire App by simulating user actions on the GUI. These are in the systemtests package.

    2. Unit tests that test the individual components. These are in seedu.ultistudent.ui package.

  2. Non-GUI Tests - These are tests not involving the GUI. They include,

    1. Unit tests targeting the lowest level methods/classes.
      e.g. seedu.ultistudent.commons.StringUtilTest

    2. Integration tests that are checking the integration of multiple code units (those code units are assumed to be working).
      e.g. seedu.ultistudent.storage.StorageManagerTest

    3. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
      e.g. seedu.ultistudent.logic.LogicManagerTest

6.3. Troubleshooting Testing

Problem: HelpWindowTest fails with a NullPointerException.

  • Reason: One of its dependencies, HelpWindow.html in src/main/resources/docs is missing.

  • Solution: Execute Gradle task processResources.

7. Dev Ops

7.1. Build Automation

See UsingGradle.adoc to learn how to use Gradle for build automation.

7.2. Continuous Integration

We use Travis CI and AppVeyor to perform Continuous Integration on our projects. See UsingTravis.adoc and UsingAppVeyor.adoc for more details.

7.3. Coverage Reporting

We use Coveralls to track the code coverage of our projects. See UsingCoveralls.adoc for more details.

7.4. Documentation Previews

When a pull request has changes to asciidoc files, you can use Netlify to see a preview of how the HTML version of those asciidoc files will look like when the pull request is merged. See UsingNetlify.adoc for more details.

7.5. Making a Release

Here are the steps to create a new release.

  1. Update the version number in MainApp.java.

  2. Generate a JAR file using Gradle.

  3. Tag the repo with the version number. e.g. v0.1

  4. Create a new release using GitHub and upload the JAR file you created.

7.6. Managing Dependencies

A project often depends on third-party libraries. For example, UltiStudent depends on the Jackson library for JSON parsing. Managing these dependencies can be automated using Gradle. For example, Gradle can download the dependencies automatically, which is better than these alternatives:

  1. Include those libraries in the repo (this bloats the repo size)

  2. Require developers to download those libraries manually (this creates extra work for developers)

Appendix A: Product Scope

Target user profile:

  • university student

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition: manage student life faster and better than a typical mouse/GUI driven app

Appendix B: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use the App

* * *

user

add a new person

* * *

user

delete a person

remove entries that I no longer need

* * *

user

find a person by name

locate details of persons without having to go through the entire list

* *

user

hide private contact details by default

minimize chance of someone else seeing them by accident

*

user with many persons in the UltiStudent

sort persons by name

locate a person easily

{More to be added}

Appendix C: Use Cases

(For all use cases below, the System is the AddressBook and the Actor is the user, unless specified otherwise)

Use case: Delete person

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

    Use case ends.

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 3a. The given index is invalid.

    • 3a1. AddressBook shows an error message.

      Use case resumes at step 2.

{More to be added}

Appendix D: Non Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 9 or higher 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.

{More to be added}

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Private contact detail

A contact detail that is not meant to be shared with others

Appendix F: Product Survey

Product Name

Author: …​

Pros:

  • …​

  • …​

Cons:

  • …​

  • …​

Appendix G: Instructions for Manual Testing

Given below are instructions to test the app manually.

These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

G.1. Launch and Shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the jar file.
      Expected: The most recent window size and location is retained.

G.2. Opening a manager

  1. Opening respective manager with the command: open

    1. Prerequisites: Currently in Homework Manager with Homework icon being highlighted.

    2. Test case: open HomeworkManager
      Expected: UI does not change changes

    3. Prerequisites: Currently in other Manager with Homework icon not being highlighted.

    4. Test case: open HomeworkManager
      Expected: HomeworkManager is opened and GUI of HomeworkManager is shown

    5. Prerequisites: Currently in Notes Manager with Notes icon being highlighted.

    6. Test case: open NotesManager
      Expected: UI does not change changes

    7. Prerequisites: Currently in other Manager with Homework icon not being highlighted.

    8. Test case: open NotesManager
      Expected: NotesManager is opened and GUI of NotesManager is shown

    9. Prerequisites: Currently in Cap Manager with Notes icon being highlighted.

    10. Test case: open CapManager
      Expected: UI does not change changes

    11. Prerequisites: Currently in other Manager with Homework icon not being highlighted.

    12. Test case: open CapManager
      Expected: CapManager is opened and GUI of CapManager is shown

G.3. Adding a homework

Adding a homework with the command: add-hw

  1. Prerequisites: HomeworkManager has to be opened to see changes on GUI. (i.e. "open HomeworkManager" command has to be ran first)

  2. Test case: add-hw mc/CS2103T hw/Tutorial 1 d/22/05/2019
    Expected: A homework will be added into the list of homework in the Homework Main Panel. The module code in which homework belongs to is also added in the Homework SubPanel list if not present before.

  3. Test case: add-hw mc/CSXXXXT hw/Tutorial 1 d/22/05/2019
    Expected: No homework is added. Error details will be shown in the status message.

  4. Other incorrect add-hw commands to try : add-hw, add-hw mc/CS2103T hw/Tutorial 1 d/dd/MM/YYYY (where dd/MM/YYYY is a past date)
    Expected: Similar to previous.

G.4. Deleting a homework entry

  1. Deleting a homework while all homework are listed with the command: delete-hw

    1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil autonmatically generates sample data when the json file is empty.

    2. Test case: delete-hw 1
      Expected: First homework is deleted from the list. Details of the deleted homework shown in the status message. Timestamp in the status bar is updated.

    3. Test case: delete-hw 0
      Expected: No homework is deleted. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect delete commands to try: delete-hw, delete-hw x (where x is larger than the list size)
      Expected: Similar to previous.

G.5. Editing a homework entry

Edit a homework while all homework are listed with the command: edit-hw

  1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil automatically generates sample data when the json file is empty.

  2. Test case: edit-hw 1 d/30/05/2019
    Expected: The deadline of the first homework is changed to 30/05/2019. Details of the edited homework shown in the status message. Timestamp in the status bar is updated.

  3. Test case: edit-hw 0
    Expected: No homework is edited. Error details shown in the status message. Status bar remains the same.

  4. Other incorrect edit commands to try: edit-hw, edit-hw x (where x is larger than the list size), edit-hw 30/05/2019
    Expected: Similar to previous.

G.6. Finding homework entries of which contains this module

Finds homework that has a homework module and displays these modules in a list with the command: find-mod

  1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil automatically generates sample data when the json file is empty.

  2. Test case: find-mod CS2030
    Expected: The homework list displays homeworks that has CS2030 as part of its homework module.

  3. Test case: find-mod x where x is any module code that is not present in the module code list.
    Expected: No homework is displayed in the homework list. Status bar shows that "0 homework listed!"

G.7. List all homework entries

Lists all existing homework entries with the command: list-hw

  1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil automatically generates sample data when the json file is empty.

  2. Test case: find-mod CS2030 followed by list-hw
    Expected: The homework list displays all existing homework entry.

G.8. Adding a note

Adding a note with the command: add-note

  1. Prerequisites: NotesManager has to be opened. (i.e. "open NotesManager" command has to be ran first)

  2. Test case: add-note mc/CS2103T n/Week 7 Tutorial Expected: A note will be added into the list of note in the Notes Main Panel.

  3. Test case: add-note mc/CSXXXXT n/Tutorial 1 Expected: No note is added. Error details will be shown in the status message.

  4. Other incorrect add-note commands to try : add-note, add-note mc/CS2103T n/(where note name is a whitespace) Expected: Similar to previous.

G.9. Deleting a note

  1. Deleting a note while all note are listed with the command: delete-note

    1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil autonmatically generates sample data when the json file is empty.

    2. Test case: delete-note 1
      Expected: First note is deleted from the list. Details of the deleted note shown in the status message. Timestamp in the status bar is updated.

    3. Test case: delete-note 0
      Expected: No note is deleted. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect delete commands to try: delete-note, delete-note x (where x is larger than the list size)
      Expected: Similar to previous.

G.10. Editing a Note

Editing a note with the command : edit-note

  1. Prerequisites: NotesManager has to be opened (i.e. open NotesManager command has to be ran first). Multiple notes in the notes list.

  2. Test case: edit-note 1
    Expected: First note will be selected and the contents of the selected note will be populated in the text area in the NotesMainPanel.

  3. Test case: edit-note 0
    Expected: No note will be selected. Error details will be shown in the status message.

  4. Other incorrect edit note commands to try: edit-note
    Expected: Similar to previous.

G.11. Saving a Note

Saving a note with the command : save-note

  1. Prerequisites: NotesManager has to be opened (i.e. open NotesManager command has to be ran first). Multiple notes in the notes list. A note has to be selected (i.e edit-note INDEX command has to ran to select a note at INDEX)

  2. Test case: save-note
    Expected: Contents of selected note will be saved. Details of note will be shown in the status message.

  3. Prerequisites: NotesManager has to be opened and no note is being selected.

  4. Test case: save-note
    Expected: Error details will be shown in the status message.

G.12. Adding a cap entry

Adding a cap entry while all cap entries are listed with the command: add-cap

  1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil automatically generates sample Data when the UltiStudent.json file is corrupted or unavailable.

  2. Test case: add-cap mc/CS3203 g/B mcs/8 sem/Y1S1
    Expected: Cap entry with module code CS1010, grade of B, 4MCs, Y1S1 is added. Details of the first cap entry shown in the status message. Timestamp in the status bar is updated. CAP score displayed is updated.

  3. Test case: add-cap mc/CS3203 g/B mcs/100 sem/Y1S1 Expected: No cap entry is added. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  4. Test case: add-cap mc/CS55555 g/B mcs/100 sem/Y1S1 Expected: No cap entry is added. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  5. Test case: add-cap mc/CS55555 g/B mcs/100 sem/Y1S3 Expected: No cap entry is added. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  6. Other incorrect edit commands to try: add-cap mc/1234 g/A+ mcs/4 sem/Y2S2 {give more}
    Expected: Similar to previous.

G.13. Deleting a cap entry

Deleting a cap entry while all cap entries are listed with the command: delete-cap

  1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil automatically generates sample Data when the UltiStudent.json file is corrupted or unavailable.

  2. Test case: delete-cap 1
    Expected: First cap entry is deleted. Details of the deleted cap entry shown in the status message. Timestamp in the status bar is updated. CAP score displayed is updated.

  3. Test case: delete-cap 0
    Expected: No cap entry is deleted. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  4. Test case: delete-cap x where x is larger than the list size
    Expected: No cap entry is deleted. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  5. Test case: delete-cap x where x is negative number
    Expected: No cap entry is deleted. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  6. Other incorrect delete commands to try: delete, delete x (where x is larger than the list size) {give more}
    Expected: Similar to previous.

G.14. Editing a cap entry

Editing a cap entry while all cap entries are listed with the command: edit-cap

  1. Prerequisites: Use the sample data that using SampleDataUtil. SampleDataUtil automatically generates sample Data when the UltiStudent.json file is corrupted or unavailable.

  2. Test case: edit-cap 1 g/A mcs/4
    Expected: First cap entry is edited. Details of the first cap entry shown in the status message. Timestamp in the status bar is updated. CAP score displayed is updated.

  3. Test case: edit-cap 0 g/A mcs/4
    Expected: No cap entry is edit. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  4. Test case: edit-cap x g/B mcs/4 where x is larger than the list size
    Expected: No cap entry is deleted. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  5. Test case: edit-cap x g/B mcs/4 where x is negative number
    Expected: No cap entry is deleted. Error details shown in the status message. Status bar remains the same. Current CAP score stays the same.

  6. Other incorrect edit commands to try: edit, edit x (where x is larger than the list size) {give more}
    Expected: Similar to previous.