Nuke User Guide v2.1

Nuke Developer Guide v2.1

By: CS2113T-T13-2 Since: Feb 2020
Go to Webpage



Table of Contents

Introduction
        • Purpose
        • Scope
        • Design Goals


Setting Up
        1. Architecture
        2. UI Component
        3. Logic Component
        4. Model Component
        5. Storage Component


Design


Structure Implementation
        1. Directory
        2. Directory Manager
        3. Directory Traverser


Command Implementation
        1. Add Command
        2. List Command
        3. Delete Command
        4. Edit Command
        5. Change Directory Command
        6. Open File Command
        7. Info Command
        8. Undo and Redo Commands


Storage Implementation


Appendix
        • Product Scope
        • User Stories
        • Non-Functional Requirements
        • Glossary
        • Manual Testing

Contact Us



Introduction

Purpose

This document describes the structure and software design decisions for the Nuke application. The Nuke application is a simple yet powerful task management application that is dedicated to providing NUS students a more efficient way to organise their modules and tasks.

Scope

This document will cover the structure and software design decisions for the implementation of Nuke. The intended audience for this document are developers, designers and software testers of Nuke or other similar task management application.

Design Goals

We have two main design goals:

Develop a structure that facilitates a more efficient organisation of the user’s tasks

This is the very value proposition of our application. We seek to make Nuke a more powerful and efficient task management system as compared to other similar products in the marketplace. As such, the structure of our application needs to be well-built and be efficient in retrieving tasks and files, as well as perform relevant operations such as adding, deleting and sorting tasks.

Enhance speed to perform operations

Another design goal we desire is to implement measures to allow the users to be able to execute their commands quickly. This would mean that the commands have to be short, but still contain the information required for the application to perform the correct command.

Back To Top



Setting Up

1.1. Prerequisites

  1. JDK 11
  2. IntelliJ IDE

1.2. Setting up the project

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

  2. Open the IntelliJ IDE. If you are not in the welcome screen, click File > Close Project to close the existing project.

  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 on Import Project

  5. Locate and select the build.gradle file, then click OK

  6. Click Open as Project

  7. Click OK to use the default settings provided

1.3. Verifying the Setup

  1. In an IntelliJ terminal, run gradlew build

  2. Navigate to the folder build > libs by executing cd build/libs/ and then run: java -jar nuke-2.0.jar

    1. To use Nuke, type a valid command into the terminal and press the enter key to run the command. e.g. Typing help and pressing the enter key will show the available commands and their respective command usage help messages.

    2. Some example commands you can try to get familiar with Nuke:

      • help: Lists the commands that Nuke supports.
        • addm cs2113t: Adds a module with module code cs2113t, Nuke will recognize it as the module Software Engineering & Object-Oriented Programming and add it to your Module List.
      • addt assignment2 -m cs2113t -c Assignment -d tmr 23:59 -p 20 : Adds a task named assignment2 which belongs to module cs2113t and category Assignment with a deadline tomorrow 23:59 and priority of 20
        • bye: Exits Nuke.

Back To Top



Design

1. Architecture

Architecture

Figure Nuke Architecture

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

Main has only one class called Nuke. It is responsible for,

There are four other components in the Nuke application.

Each of the four components

For example, the Storage component defines it’s API in several classes including Encoder and Decoder, and exposes its functionality by invoking different method in these classes by StorageManager class.

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 addm CS2113T. (As the Storage component will only be used when launching and exiting the applicatio, here the storage component is omitted.)

interactions.jpg

Figure Components interactions

Back To Top


2. UI Component

Classes used by UI component are in the seedu.nuke.ui package.

3. Logic Component

Classes used by Logic component are in the seedu.nuke.data package, seedu.nuke.parser package, DirectoryTraverse.java in seedu.nuke.directory package and Executor.java in seedu.nuke package.

The diagram below shows the Logic Component of the Nuke application in our current implementation:

logic component

Figure Logic Component

4. Model Component

More information about the Model Component can be found here.

5. Storage Component

More information about the Storage Component can be found here.

Back To Top



Structure Implementation

This section shall discuss about our implementation of the overall structure of the Nuke application. We will highlight three main features of the current structure: Directory, Directory Manager and Directory Traverser.

1. Directory

Overview

The Nuke application attempts to simulate the structure of a Directory Tree 🌳 (folder sub-folder) structure. This means that there is a hierarchy for different directories in the Tree. Each directory will have a corresponding parent directory, with the exception of the base directory. In Nuke, this base directory is called the Root.

There are altogether 5 levels in the current implementation of Nuke's Directory Tree:
Table Directory Levels
Directory Level Description
Root The base of the Directory Tree. Only one root exists in the entire Tree.
Module The second level of the Directory Tree.
Category The third level of the Directory Tree.
Task The fourth level of the Directory Tree.
File The last level of the Directory Tree.


The parent directory of each directory is the one at the previous level. The Root's parent is NULL, i.e. nothing.

Note
The hierarchy of the Directory Tree set in place has to be followed strictly. That means, their levels in the Tree can never be changed.

Implementation

The basic class diagram of the structure is shown below. A more detailed class diagram with the attributes for each directory is shown here.

directory class diagram basic
Figure Directory Class Diagram (Basic)

The Module, Category, Task and File Directories each have their own set of attributes. Also, apart from the File directory, each of them have a corresponding Directory Manager class that stores and manages the operations regarding the child directories. For example, a Module has a CategoryManager class that stores the module's categories, and manages their operations (such as adding and deleting).

We will show a more detailed class diagram, as well as describe each of the Directory's attributes below:


directory class diagram
Figure Directory Class Diagram

Root

The Root Directory is the base of the entire Directory Tree. Only one root exists in the entire Tree. The root does not have any attributes, and its parent is NULL.

Module

The Module Directory is the second level of the Directory Tree. It corresponds to a module. A module has a module code and title. It also has a Category Manager which stores categories to categorise the user's tasks, such as "Lecture", "Tutorial" and "Assignment".


Info
In our current implementation, when a user adds a module, the application automatically adds four categories into the module. They are "Lecture", "Tutorial", "Assignment" and "Lab". These are common categories and are added automatically to improve usability for users, since they do not need to add them on their own.

Category

The Category Directory is the third level of the Directory Tree. It corresponds to a category. A category consists of a name and a priority to indicate the importance of the tasks in that category. Each category has a Task Manager that stores the user's tasks.

Task

The Task Directory is the fourth level of the Directory Tree. It corresponds to a task. A task has several attributes, namely the description, deadline of the task if any, priority and the done status of the task. Each task contains a File Manager that stores the task's files.

File

The File Directory is the last level of the Directory Tree. It corresponds to a file. The file must have a file name, file path, and its original file path It does no have a corresponding Directory Manager.


Info
The original file path is the path to where the original file is taken from in the application. In our current implementation, Nuke will then make a copy of the file and save it into a new location, and the path to the new location is stored in the file path attribute.


Back To Top

2. Directory Manager

Overview

The Directory Manager is a collective term used to refer to the Module Manager, Category Manager, Task Manager and File Manager. The Directory Manager manages the storage and operations of the Directory it is managing. For example, the ModuleManager object will manage Module objects.

Implementation

The Directories in the Directory Manager are stored in an ArrayList.

The Directory Manager classes also contain very similar methods to carry out operations regarding its Directories. For example, in the ModuleManager class, there are:
The Directories and Directory Managers together make up the Model component of the Nuke application.

Back To Top

Design Considerations

Structure Decision

Directory Operations

Back To Top

3. Directory Traverser

Overview

The Directory Traverser is a very fundamental feature that utilises the Directory Tree structure of Nuke to carry out its operations. In particular, it plays a pivotal role in the Change Directory command to traverse up and down from the current Directory.

The Directory Traverser also helps to fill in the missing path attributes in various commands by using the information from the current and parent Directories. For example, if a user is at the Module level, with module code CS2100, and wants to add a category, he does not have to enter the directory path to the module in the command as such: addc toAdd -m cs2100. Instead, he can just type addc toAdd. This also works when the user is at the Category, Task and File levels.

Implementation

directory traverser class diagram
Figure Directory Traverser Class Diagram

The DirectoryTraverser class is a static class which has several public static methods. That means other classes can use the DirectoryTraverser class's methods without having to instantiate a DirectoryTraverser object.

DirectoryTraverser stores the current path information as a Stack. When traversing down to a child Directory, it pushes the child Directory into the Stack. Similarly, when traversing up to its parent Directory, it pops the current Directory out of the Stack. This helps to track what is the current Directory, which will always be at the top of the Stack.


directory traverser traverse down
Figure Directory Traverser Traverse Down

directory traverser traverse up
Figure Directory Traverser Traverse Up

As described in the Overview, the DirectoryTraverser class has two main functions:

Traversal
The DirectoryTraverser class contains three main methods to facilitate traversing up and down Directories. They are:

  1. findNextDirectory(nextDirectoryName: String) – Finds a present Directory in the next Directory level with the matching nextDirectoryName
  2. traverseDown(nextDirectory: Directory) – Traverses down to the nextDirectory by pushing the nextDirectory into the directoryStack
  3. traverseUp() – Traverses up to the parent Directory by popping the top Directory from the directoryStack

Info
The Root Directory and the File Directory are the first and last directories in the Directory Tree respectively. If the user attempts to traverse down up the Root Directory, or traverse down a File Directory, an error message will be shown to the user instead. 😯

The above three methods plays an important role in the Change Directory command.

Attributes Matching
Matching attributes to fill in the missing path attributes given by the user is not so straightforward. DirectoryTraverser has to search through each of the Directory in its directoryStack to extract the relevant information.

At times, the user may be at an inadequate Directory level for DirectoryTraverser to fully extract the path information. In this case, DirectoryTraverser has to be able to recognise this, and throw an exception 😞. For example, if the user is at the Root level and enters addt do task -c Assignment to add a task, in our current implementation, the following will happen:
  1. DirectoryTraverser will attempt to fill in the missing path attribute for the module
  2. However, since the user is at the Root level, DirectoryTraverser is unable to fill the missing path to the module
  3. DirectoryTraverser will throw an exception and an error message is shown to the user to either move to the correct level, or enter the full Directory path

To support the attributes matching feature, DirectoryTraverser has 2 distinct groups of methods, with one method for each Directory level from Root to File (i.e. in total 8). The methods are:
  1. getBaseModule() – Gets the parent Module Directory, or the current Directory if it is at the Module level
  2. getBaseCategory() – Gets the parent Category Directory, or the current Directory if it is at the Category level
  3. getBaseTask() – Gets the parent Task Directory, or the current Directory if it is at the Task level
  4. getBaseFile() – Gets the current Directory if it is at the File level
  5. getModuleDirectory(String) – Gets the Module level Directory after first filling missing path attributes
  6. getCategoryDirectory(String, String) – Gets the Category level Directory after first filling missing path attributes
  7. getTaskDirectory(String, String, String) – Gets the Task level Directory after first filling missing path attributes
  8. getFileDirectory(String, String, String, String) – Gets the File level Directory after first filling missing path attributes

As of the current implementation, the above methods are sufficient for the attributes matching property.


Back To Top

Design Considerations

Attributes Matching

Info
The commands targeting the File Directroy requires the longest path. For example, the format for the add file command would look something like addf assignment_1 -m ma1521 -c Assignment -t do assignment. Having the user to constantly type such long commands 😫 would really inconvenience them.

Back To Top



Command Implementation

This section will describe the significant details of how the commands in Nuke are being implemented.


Below is a diagram which summarises the commands in the current Nuke application.

commands
Figure Nuke Commands

1. Add Command

Overview

The add feature adds modules, categories, tasks and tags into the Module, Category and Task List respectively.

ClassDiagramAdd.jpg

Figure Add Command Classes Diagram

1.1. Add Module Command

The add module feature enable the user to add modules into the Module List.

When the user first requests to execute the addm command(assuming the command format given is valid) to add a module by providing its name, the application will parse the input after addm command word as the module code. From here, there are three possible outcomes:

  1. The module specified by the user is not provided by NUS – No module will added.
  2. The module specified by the user is already added – No module will be added.
  3. The module specified by the user is provided by NUS and have not been added – Module will be added.

Implementation

This feature is facilitated by the AddModuleCommand class which add the modules specified by the user. It overrides the execute() method which extends from the abstract AddCommand class which extends from the abstract Command class. The execute() method’s role is to execute the adding module operation and do necessary checks .

The AddCommand will first try to call the static method add in ModuleManager class, which will try to add the module specified by the user, exception will thrown according the following rules:

  1. DuplicateModuleException will be thrown if the module specified by the user is contained in the ArrayList named moduleList in ModuleManager class.
  2. ModuleNotProvidedException will be thrown if the module code specified by the user is not contained in the HashMap named modulesMap in ModuleManager class.


Back To Top

Example Usage

The addition of modules will be illustrated as follows.

James is a user and wants to add the module with the module code of “CS3235”. Assume that he has the current modules:

+--------------------------------------------------------------------------------------------------+
 NO |  MODULE CODE   |                                 MODULE TITLE
+--------------------------------------------------------------------------------------------------+
 1  |     CS1231     |                             Discrete Structures
 2  |     CS2100     |                            Computer Organisation
 3  |     CS2113     |              Software Engineering & Object-Oriented Programming
+--------------------------------------------------------------------------------------------------+
Total modules: 3
+--------------------------------------------------------------------------------------------------+

James will simply enter the command addm cs3235

After the input is parsed as an add module task and executed, the AddModuleCommand#execute() will call ModuleManager#add() to add the module cs3235. In the ModuleManager#add() method, it will call ModuleManager#contains() to check if the module cs3235 exists in the ArrayList named moduleList , then it will check if the module code “cs3235” is a key in the HashMap named modulesMap, after all, it will instantiate an Module object with the module code “CS3235” and respective title “Computer Security”, then add the object into the moduleList.

James receive the following feedback:

 root :
 addm cs3235
 SUCCESS!! Module CS3235 Computer Security has been added.
   
 root :
 lsm
 Here are what you are looking for...
   
 +--------------------------------------------------------------------------------------------------+
  NO |  MODULE CODE   |                                 MODULE TITLE
 +--------------------------------------------------------------------------------------------------+
  1  |     CS1231     |                             Discrete Structures
  2  |     CS2100     |                            Computer Organisation
  3  |     CS2113     |              Software Engineering & Object-Oriented Programming
  4  |     CS3235     |                              Computer Security
 +--------------------------------------------------------------------------------------------------+
 Total modules: 4
 +--------------------------------------------------------------------------------------------------+


Below is a sequence diagram to illustrate the above example scenario.

image-20200326014336120 Figure Add Module Command Class Diagram

Back To Top

1.2. Add Category and Task Commands

Since add category and add task feature are implemented in a similar pattern, they can be explained together.

The add category/task enable the user to add category/task/tag into Category/Task/Tag List.(One to one correspondence, which means the user can only add category to Category List, task to Task List).

When the user first request to execute the add command(assuming the command format given is valid) to add a category/task by providing its name, the application will parse the input after addm /addc command word as the name for category/task. From here, there are three possible outcomes:

  1. The specified upper parent directory does not exist. – No category/task will be added.
  2. The name of the specified category/task already exist. – No category/task will be added.
  3. The specified upper parent directory exist and the name of the specified category/task does not exist. – The specified category/task will be added.

Implementation

This feature is facilitated by the AddCategoryCommand and AddTaskCommand class which add the corresponding category or task respectively.

The above-stated two classes overrides the execute() method which extends from the abstract AddCommand class which extends from the abstract Command class. The execute() method’s role is to execute the adding category/task operation and do necessary checks.

The AddCategoryCommand and AddTaskCommand will first call the getParentDirectory() method to get the parent directory, then it will instantiate a Category/Task object and try to call add method in their respective parent directory class to add the new object, exception will be thrown according to the following rules:

  1. ModuleNotFoundException will be thrown if the specified module code does not exists in the ArrayList of Module when adding a new category or task.
  2. CategoryNotFoundException will be thrown if the specified category name does not exists in the ArrayList of Category in CategoryManager in Module when adding a new task.
  3. IncorrectDirectoryLevelException will be thrown if the user is performing theaddc/addt command in the wrong directory without specifying their full parent directories.(For example, when user trying to execute addc in a Root/Task directory, or trying to execute addt in a Root/Module directory)
  4. DuplicateTaskException/DuplicateCategoryException will be thrown if the name of the category/task already exist in the current directory.

Below are the class-diagram for the involved classes:

to-do: add the class-diagram

Example Usage

The addition process for category and task are similar. In this example, the addition process for category will be illustrated as a series of steps.

James is a user and wants to add a category named “misc” under the module cs3235. Assume that he has the current Module List and current Category List in the module cs3235:

+--------------------------------------------------------------------------------------------------+
 NO |  MODULE CODE   |                                 MODULE TITLE                       
+--------------------------------------------------------------------------------------------------+
 1  |     CS1231     |                             Discrete Structures                    
 2  |     CS2100     |                            Computer Organisation                   
 3  |     CS2113     |              Software Engineering & Object-Oriented Programming    
 4  |     CS3235     |                              Computer Security                     
+--------------------------------------------------------------------------------------------------+
Total modules: 4
+--------------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------+
 NO |     MODULE     |                                CATEGORY                                | PTY
+--------------------------------------------------------------------------------------------------+
 1  |     CS3235     |                               Assignment                               |  4
 2  |     CS3235     |                                  Lab                                   |  3
 3  |     CS3235     |                                Lecture                                 |  1
 4  |     CS3235     |                                Tutorial                                |  2
+--------------------------------------------------------------------------------------------------+
Total categories: 5
+--------------------------------------------------------------------------------------------------+
  1. James has two choices:

    1. enter cd cs3235 to enter the module directory then enter addc misc to add the category.
    2. enter addc misc -m cs3235 to add the category at the root directory.

    Suppose James use the first method, after the second input, the input is parsed as an add task command and executed, the AddCategoryCommand#execute() will call AddCategoryCommand#getParentDirectory() to get the current parent directory, then it will instantiate an Category object with the name “misc”. After which CategoryManager#add() will be called to add the new object. In the CategoryManager#add() method, it will call CategoryManager#contains() method to check if the current parent directory contains the category with name “misc”, finally add the object into the ArrayList of categoryList.

  2. James receive the following feedback:

    root :
    addc misc
    SUCCESS!! Category misc is created.
    

Below is a sequence diagram to illustrate the above example scenario.

image-20200326014336120 Figure Add Module Command Sequence Diagram

Design Considerations

Character Limit

Info
The word limit that we have implemented in Nuke are the following:

Module Code: No character limit, but has to be an NUS provided module
Category Name: 15 characters
Task Description: 25 characters
File Name: 30 characters

These numbers are chosen in view of the realistic length of words a user will usually use for such names. So in most cases, the user should not be exceeding the character limit 😏.

2. List Command

Overview

The List feature lists out modules, categories and tasks from the Module, Category and Task List respectively.
When the user first requests to execute the list command to list out directory by providing its name, the application will first filter for directories with matching names. From here, there are three possible outcomes:

  1. There are no matches – Nothing is listed out.
  2. There are matches – The list of matches will be shown to the user.

Implementation

ClassDiagramList.jpg

Figure List Command Class Diagram

The ListModuleCommand, ListCategoryCommand, ListTaskCommand, ListFileCommand, DueCommand, ListModuleTaskCommand, ListTaskSortedCommand classes in the application facilitates this list feature. They are in charge of listing out modules, categories, tasks, files, all tasks at the specified time period, tasks of module in ascending order of deadline and all undone tasks sorted by deadline or priority respectively.

As shown in the figure above, those seven classes each extends from the abstract ListCommand class. They also override the ancestor Command class’s execute() method, which role is to list out desired entries to the user.

The ListCommand class in turn extends the FilterCommand abstract class. The FilterCommandClass contains the following vital methods for filtering:

Lastly, the FilterCommand class extends the abstract Command class that contains the execute() method to execute the actual list command.

Example Usage

The listing process for modules, categories, tasks, files, all tasks at the specified time period, tasks of module in ascending order of deadline and all undone tasks sorted by deadline or priority are similar. In this example, the listing process for modules will be illustrated as a series of steps.
James is a user and wants to list out all of his modules with moduleCode begin with “CS”. Assume that he has the current Module List:

+--------------------------------------------------------------------------------------------------+
 NO |  MODULE CODE   |                                 MODULE TITLE                                 
+--------------------------------------------------------------------------------------------------+
 1  |     CS2101     |             Effective Communication for Computing Professionals              
 2  |    CS2113T     |              Software Engineering & Object-Oriented Programming              
 3  |     CS3230     |                      Design and Analysis of Algorithms                       
 4  |     CS3235     |                              Computer Security                               
 5  |    GEH1036     |                           Living with Mathematics                            
 6  |    IFS4103     |                         Penetration Testing Practice                         
+--------------------------------------------------------------------------------------------------+
Total modules: 6
+--------------------------------------------------------------------------------------------------+


James will first enter the command to list out modules with moduleCode begin with “CS”:
lsm CS
After the input is parsed as a list module command and executed, the ListModuleCommand#execute() will call FilterCommand#createFilteredModuleList() to create the filtered list of modules containing the Modules with moduleCode begin with “CS”. ListModuleCommand#execute() will then call its parent class’s method FilterCommand#sortModuleList(filteredModuleList) to sort the modules by their respective moduleCode. And finally the sorted Arraylist of Modules is used to instantiate a CommandResult object and returned, and ui#showResult(commandResult) will be called to show the result to the user. And Listing process ends.

Below is a sequence diagram to illustrate the above example scenario.

List Module Command Sequence Diagram
Figure List Module Command Sequence Diagram



3. Delete Command

Overview

The delete command deletes directories from their respective lists. For example, a user can delete a module from the Module List.
When the user first requests to execute the delete command to delete a directory by providing its name, the Nuke application will first filter for directories with matching names. From here, there are three possible outcomes:
  1. There are no matches – Nothing is deleted.
  2. There is one match – A prompt will be given to the user to confirm the deletion.
  3. There are multiple matches – The list of matches will be shown to the user, and the user chooses which ones to delete. A further prompt will be given to confirm the deletion(s).

Implementation


delete command class diagram
Figure Delete Command Class Diagram


The delete commands are similar to each other, and targets to delete directories of a specific directory level. For example, the DeleteTaskCommand class will only delete tasks (and not modules, categories or files).

Like the list commands, the delete commands function with a filter property. That is to say, the delete commands will first filter for the possible directories to delete based on the user-provided keywords. If there are multiple matches after the filtering, the user will be prompted to choose which of the directories they wish to delete.

Since the delete commands are quite similar to the list commands, the DeleteCommand class extends from the same FilterCommand class as the ListCommand class. The DeleteCommand class thus inherits the same methods in the FilterCommand class.

Each of the delete commands extends from the abstract DeleteCommand class. The DeleteCommand class has an abstract method, executeInitialDelete(), and each of the delete commands must implement this method. The role of executeInitialDelete() is to prepare the necessary prompt to show the user, depending on the number of filtered matches (See above).

![prompt command class diagram](/tp/images/dg_prompt_class.png) Figure Prompt Command Class Diagram
Two prompt commands are involved in the deletion process:
  1. ListNumberPrompt manages the event after the user has input the list numbers of the directories to delete when there are multiple matches.
  2. DeleteConfirmationPrompt manages the event after the user has responded to the confirmation prompt to delete the directories
Info
The ListNumberPrompt class will only be executed if there are multiple matches. Otherwise, only the corresponding DeleteCommand and DeleteConfirmationPrompt objects will be executed in the deletion process.

The deletion process can thus be broken down into 3 stages. We provide for you the relevant sequence diagrams to help you to see how each stage works in our current implementation of the delete command.
The user, say Peter in this example, will first request the directory(s) he wishes to be deleted. Assume Peter currently has these modules in his Module List:


+--------------------------------------------------------------------------------------------------+
 NO |  MODULE CODE   |                                 MODULE TITLE                                 
+--------------------------------------------------------------------------------------------------+
 1  |     CS1231     |                             Discrete Structures                              
 2  |     CS2101     |             Effective Communication for Computing Professionals              
 3  |     CS2102     |                               Database Systems                               
 4  |    CS2113T     |              Software Engineering & Object-Oriented Programming              
 5  |     CS3235     |                              Computer Security                               
 6  |    GEH1036     |                           Living with Mathematics                            
 7  |    IFS4103     |                         Penetration Testing Practice                         
+--------------------------------------------------------------------------------------------------+
Total modules: 7
+--------------------------------------------------------------------------------------------------+


Now, Peter wishes to delete modules CS1231 and CS2102. He enters delm cs to execute the command.

The Nuke Parser will parse the input as a delete module command. The DeleteModuleCommand object is instantiated and executed. The object will first filter modules containing the keyword "cs". This is done by the FilterCommand#createFilteredModuleList() method. Then, DeleteModuleCommand will call its own executeInitialDelete(filteredList) method to prepare the prompt to ask Peter to choose which modules he would like to delete.


The sequence diagram for stage :

delete command sequence diagram
Figure Delete Command Sequence Diagram 1

Peter receives the following prompt:
Multiple matching modules were found.
+--------------------------------------------------------------------------------------------------+
 NO |  MODULE CODE   |                                 MODULE TITLE                                 
+--------------------------------------------------------------------------------------------------+
 1  |     CS1231     |                             Discrete Structures                              
 2  |     CS2101     |             Effective Communication for Computing Professionals              
 3  |     CS2102     |                               Database Systems                               
 4  |    CS2113T     |              Software Engineering & Object-Oriented Programming              
 5  |     CS3235     |                              Computer Security                               
+--------------------------------------------------------------------------------------------------+
Total modules: 5
+--------------------------------------------------------------------------------------------------+

Enter the list number(s) of the modules to delete.
He then proceeds to enter the corresponding list numbers 1 3 to delete modules CS1231 and CS2102.

Note
Since there are multiple matches, the application will first request for the user to choose the directories he wants to delete. If there is only a single match, this stage is skipped, and the application will continue at stage

After the Parser has parsed the list numbers, the ListNumberPrompt object is constructed. ListNumberPrompt will prepare the prompt for the delete confirmation, and then calls its executePromptConfirmation(filteredList, MODULE) method.

This is the sequence diagram for stage :

prompt command sequence diagram
Figure Delete Command Sequence Diagram 2

Peter receives the confirmation prompt:
Confirm delete these modules?
CS1231 Discrete Structures
CS2102 Database Systems
He enters yes to confirm the deletion.

At the backend, the Parser will parse the confirmation, and constructs the DeleteConfirmationPrompt object. After getting the list of modules to delete, DeleteConfirmationPrompt then calls executeMultipleDelete(filteredList, MODULE) to delete Peter's selected modules from his Module List.

Below is the sequence diagram for stage :

confirm command sequence diagram
Figure Delete Command Sequence Diagram 3


Peter receives the final message:

SUCCESS!! Module(s) have been deleted.
and the delete process ends.

Back To Top

Design Considerations

Filtering for Deletion

Prompts for Deletion

Back To Top



4. Edit Command

Overview

The edit command edits the attributes of a directory. For example, user can edit a category's name and priority. For tasks, the user is also able to mark them as done.

Implementation


edit commands class diagram
Figure Edit Commands Class Diagram

The edit commands all work in a similar manner. As seen in the class diagram above, each of the edit commands extends from the abstract EditCommand class. The EditCommand class has an abstract method, toEdit(Directory), which is to be implemented by each of the edit commands.

The edit command will first checks if the attribute String exceeds a fixed length by its own isExceedLengthLimit() method (See here for the considerations of the length limit). It then calls DirectoryTraverser class to get the appropriate Directory to edit.

Info
If the attribute String exceeds the length limit, an exception will be thrown 😐 and the user will be shown an error message.

In addition, for EditCategoryCommand and EditTaskCommand, it will fill in any missing attributes not specified by the user in their input. This is done through the command's fillAttributes() method.

Finally, the edit command will perform the edit() method to edit the Directory.
Info
The Parser object also helps to check if the user's input contains attributes of the directory to edit. For example, if a user executes the edit module command, but does not enter a new module code to be edited, the application will prompt the user to enter a new module code.


An example sequence diagram is shown below when a user requests to edit a category:

edit command sequence diagram
Figure Edit Command Sequence Diagram

Back To Top

Design Considerations

Editing Task

Edit Multiple Attributes

Back To Top



5. Change Directory Command

Overview

The change directory command traverses the user up and down the Directory Tree, much like how the Linux Shell operates. In other words, the user enters the directory name to traverse to that directory, or .. to traverse to the parent directory

Implementation

The change directory command uses various methods from the DirectoryTraverser class in its execution.

If the user wants to traverse down to a directory, the ChangeDirectoryCommand will call DirectoryTraverser#findNextDirectory(nextDirectoryName) to get the Directory to traverse to. Then, ChangeDirectoryCommand will call DirectoryTraverser#ftraverseDown(nextDirectory) to move the user to that directory.

If the user want to traverse up from the current directory instead, ChangeDirectoryCommand will call DirectoryTraverser#traverseUp() to bring the user back to the parent directory.


Info
The Root Directory and the File Directory are the first and last directories in the Directory Tree respectively. If the user attempts to traverse down up the Root Directory, or traverse down a File Directory, an error message will be shown to the user instead. 😦

Shown below is the sequence diagram when a user executes the change directory command to traverse down to another directory.

change directory command sequence diagram
Figure Change Directory Command Sequence Diagram

Back To Top

Design Considerations

Traversal Method

Back To Top


6. Open File Command

Overview

The open file command opens up the file(s) of a task specified by the user. User can choose whether to open a single file in the task, or all the files in the task.

Implementation

The implementation of the Open File command uses two important Java APIsjava.io.File and java.awt.Desktop. The first API is responsible for operations involving file access, while the second API is used to open the file to the Desktop.

The OpenFile object first obtains the list of files from the task to open via the OpenFile#getFilesToOpen() method. Then, OpenFile executes the OpenFile#openFiles() method to open each of the files in the list.
Info
If there is an error opening a particular file in the list 😖, the opening process will not be terminated immediately. Instead, the application will continue to open the rest of the files in the list.
After it has gone through the list, it will then show the user the files that were not opened due to an error.

This is done by collecting the file names of the failed to open files into a String, and thereafter throw an exception with the String of file names as the message.



Below is a sequence diagram of how the open file command operates:

open file command sequence diagram
Figure Open File Command Sequence Diagram

Back To Top

Design Considerations

Allow opening of multiple files

Back To Top


7. Info Command

Overview

The info command shows the information of the current directory that the user is in. For example, when in the Module directory, the info command will show the module code, module title and the module's category list to the user.

Implementation

The implementation of this command is quite straightforward.
The InfoCommand object will call for the DirectoryTraverser object to get the current Directory. Then, the information of the Directory is obtained by calling Directory#toString(). The list to show is generated by the InfoCommand#getListToShow() method.
These information will eventually be shown to the user through the Ui.

The sequence diagram of what happens when a user executes the info command is as illustrated:

info command sequence diagram
Figure Info Command Sequence Diagram

Back To Top


8. Undo and Redo Commands

Overview

The undo and redo commands work hand in hand with each other. The undo command undoes a change made to the Directory List. Change here refers to adding, deleting or editing items to the list. The redo command reverts the effect of the undo command.

Implementation

The state of the directories is being maintained by the ScreenShotManager class. This is done via two stacks, one for undo, and the other for redo.

When the application starts, both stacks are empty. After the applications loads the saved directory list file, the current state of the directories is pushed into the undo stack.

undo command init

When a change is made to the list from a successful add, delete or edit command, the new state is pushed into the undo stack. This is done by the ScreenShotManager's saveScreenShot() method.
The new state is also saved by the application. See here to find out more about the storage implementation.

undo command change 1

If the user calls for the undo command, the top-most state in the undo stack is removed and pushed into the redo stack. Then, the list will reload to the current top-most state in the undo stack, which is actually the previous state. All of these are done by the ScreenShotManager's undo() method.

undo command undo

Conversely, If the user calls for the redo command, the top-most state in the redo stack is removed and pushed back into the undo stack. Then, the list will reload to the current top-most state in the undo stack, which is actually the state which was previously undone. These are done by the ScreenShotManager's redo() method.

undo command redo

If another change is made to the list, the redo stack is emptied, and the new current state is added into the undo stack (saveScreenShot()).

undo command change 2

The process continues.
Note
An error message will be shown to the user when the user tries to undo when no recent change was made, such as at the start of the application, and when the user tries to redo when nothing was recently undone.

This is done in the ScreenShotManager class by checking if the undo stack contains more than one element (first element is the start-up state), and if the redo stack is not empty respectively. If checking fails, an exception will be thrown. 😑

Below is a sequence diagram of the undo command in action:

undo command sequence diagram
Figure Undo Command Sequence Diagram

Back To Top

Design Considerations

Number of undos allowed

How undo and redo executes

Back To Top



Storage Implementation

Overview

The storage operations, such as saving and loading of data, are implemented through the StorageManager class. The saving of the Directory Tree data is performed by the saveList() method, and the loading of the Directory Tree data is performed by the loadList() method.

In our current implementation, the data is saved into a save.txt file in the user's device.

Implementation

Encoding and Decoding

storage manager class diagram Figure Storage Manager Class Diagram

The StorageManager class is supported by two other vital classes – Encoder and Decoder.

Encoder
The Encoder class contains methods to facilitate file saving. It converts the various Directory objects in the Directory Tree into a String format. This conversion is performed by the encode() method through a depth-first method.

The encoded String is then saved into a save.txt file in the user's device by the StorageManager class.

Decoder
The Decoder class, conversely, contains methods to facilitate file loading. It converts the encoded String in the save.txt file back into the Directory Tree. This conversion is performed by the decode() method, and also via a depth-first method.

The decoded Directory Tree is then loaded into the application by the StorageManager class.

The StorageManager, Encoder and Decoder classes make up the Storage Component of Nuke.
Saving
In our current implementation of Nuke, the Directory Tree is saved every time a change is made. Change here refers to operations that changes the contents in the Directory Tree , such as successful adding, deleting and editing of the directories.

The StorageManager has a static boolean variable isToSave, which is set to false by default. It also has a static method setIsSave(), which sets the isToSave variable to true.

When a change is made through a command, StorageManager#setIsSave() is called. This will notify the StorageManager to call saveList() to save the Directory Tree.

Below is a code snippet of the AddModuleCommand when the StorageManager#setIsSave() is called:
@Override  
public CommandResult execute() {
	... ...
	
	ModuleManager.add(toAdd);
	StorageManager.setIsSave();  
	return new CommandResult(... ...);
	... ...
}
Below is a code snippet in the Main class when the StorageManager#saveList() is called:
private void runCommandLoopUntilExitCommand() {
	... ...

	if (StorageManager.isToSave()) {  
	    ... ... 
        storageManager.saveList();  
		... ...
	    ScreenShotManager.saveScreenShot();  
	}
	... ...
}
Info
Notice that the ScreenShotManager#saveScreenShot() is also called after the StorageManager saves the Directory Tree. The ScreenShotManager class is responsible for performing undo and redo operations in the application.

For more information about the ScreenShotManager class or the undo and redo commands, click here.

Here is a sequence diagram of what happens during saving after a successful add command:

storage manager sequence diagram
Figure Storage Manager Sequence Diagram

Back To Top

Design Considerations

When to Save

Storage Security


Info
As of now, the current implementation of saving does not use any encryption schemes. This is generally because the Nuke application is intended for personal use, and the data involved is not intended to contain any personal information,

However, for future implementations of the application, we are looking towards extending the application into the cloud and provide other services as well. At that point, personal data could be involved, and we will definitely implement measures to ensure the security of the user's data 😄.

Back To Top



Appendix

Product Scope

Target User Profile

Value proposition

Manage tasks faster and with greater efficiency due to greater organisation of tasks. The application is specifically designed for NUS students to manage academic tasks. Files can be attached to tasks, and opened directly through the application.

Back To Top

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 learn about existing features and how can I use them
* * * student add modules\tasks have track on tasks of different modules
* * * student delete modules\tasks remove modules and tasks I do not need to keep on track anymore
* * * student count my total tasks keep track of how many tasks I have left and plan my time better
* * * student add different priorities to tasks manage my time and do the most important things first
* * * student edit modules and tasks correct or change some attributes
* * * student constantly check the deadline of tasks in ascending order get tasks done on time
* * * student receive a reminder of urgent tasks know which tasks should be done first
* * * student sort my tasks in terms of certain criteria view my tasks of highest priorities
* * * student add tags to tasks filter and view tasks with respect to certain tags
* * student receive a reminder of expired tasks know I passed the deadline
* * student receive a reminder of tasks which are near the deadline never forget to finish them on time.
* * student attach files to tasks open the files from the program when I start on the tasks
* * student organize my files according modules and tasks enjoy the ease of picking out relevant files
* * student filter tasks with certain criteria easily view what is relevant at the moment
* * student enter shorter commands save my time
* student get the files that will be covered one week ahead prepare(print) them on weekends
* student add any custom modules not restricted to a specific category of task

Back To Top

Non-Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 11 or above installed.
  2. User with above average typing speed for English text (not coding) should be able to utilize the product to manage tasks more efficiently compared to using a mouse.
  3. Data entered by the user should be able to saved and carried forward for the next time usage.
  4. The file containing the saved data should be portable so that the user can transfer to the other machine with any mainstream OS and continuing using the app without any additional configuration.
  5. The product should be able to run without any noticeable sluggishness in performance for typical usage when dealing with up to 100 academic tasks.
  6. The product should never crash and able to handle any input from the user.
  7. Should work on both 32-bit and 64-bit environments.
  8. Should not exceed 30MB in size given normal usage.

Back To Top

Glossary

Mainstream OS

​ Windows, Linux, Unix, OS-X

Average typing speed

​ 40 words per minute

Depth First

To go recursively downwards until the bottom before back-tracking


Back To Top

Instructions for Manual Testing

Given below are instructions to test the application manually.

Note
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. We also recommend testers to have a stable Internet connection when carrying out the testing so that the application can successfully retrieve the module information from NUSMods API

1. Launch and Shutdown

  1. Initial launch
    1. Download the jar file from the release page and copy into an empty folder.
    2. Launch a terminal and navigate the to folder containing the jar file
    3. Run the jar file by entering command java -jar Nuke.jar and hit enter(replace Nuke.jar by the actual file name you downloaded from the release page)
    4. Expected output: Nuke startup screen and welcome message is displayed
  2. Shut down of application
    1. Enter command bye and hit enter
    2. Expected output: Nuke program terminates with farewell message displayed.

2. Add Command

Note
All the Add Commands below are assumed to be executed at the root directory.
  1. Add module
    1. Correct usage:
      1. Test case: addm cs2113t
      2. Expected: the program will prompt the user with message: SUCCESS!! Module CS2113T Software Engineering & Object-Oriented Programming is added.
    2. Wrong usage:
      1. Test case: addm cs1111
      2. Expected: the program will prompt the user with message: Sorry, the module is not provided by NUS currently.
      3. Test case: addm cs2113t after executing addm cs2113t
      4. Expected: the program will prompt the user with message: Sorry, the module already exists.
  2. Add category
    1. Correct usage:
      1. Test case: addc Project -m cs2113t after adding cs2113t as module
      2. Expected: the program will prompt the user with message: SUCCESS!! Category Project is created.
    2. Wrong usage:
      1. Test case: addc Tutorial -m cs2113t after adding cs2113t as module
      2. Expected: the program will prompt the user with message: Sorry, the category already exists.
      3. Test case: addc Project -m cs3235 without adding cs3235 as module
      4. Expected: the program will prompt the user with message Sorry, the module is not found.
  3. Add task
    1. Correct usage:
      1. Test case: addt assignment2 -m cs2113t -c Assignment -d tmr 23:59 -p 15 after adding cs2113t as module
      2. Expected: the program will prompt the user with message: SUCCESS!! Task assignment2 is created.
    2. Wrong usage:
      1. Test case: addt assignment2
      2. Expected: the program will prompt the use with message: Sorry, unable to execute the command at the current directory level. Either move to the appropriate directory level, or enter the full directory path.
      3. Test case: addt testingaveryveryveryveryverylongstring -m cs2113t -c Assignment -d tmr 23:59 -p 15 after adding cs2113t as module
      4. Expected: the program will prompt the user with message: Sorry, the task description cannot exceed 25 characters.
  4. Add file
    1. Correct usage:
      1. Test case: addf test.pdf -m cs2113t -c Assignment -t assignment2 -f c:\users\null\downloads\assignment2.pdf after adding an assignment2 task under Assignment category and cs2113t module, assuming c:\users\null\downloads\assignment2.pdf exists.
      2. Expected: the program will prompt the user with message: SUCCESS!! File test.pdf is added.
    2. Wrong usage:
      1. Test case: addf test.pdf -m cs2113t -c Assignment -t non-exist-task -f c:\users\null\downloads\assignment2.pdf without adding the respective task
      2. Expected: the program will prompt the user with message: Sorry, the task is not found.
  5. Add tag

    1. Correct usage:
      1. Test case: addg urgent -m cs2113t -c Assignment -t assignment2 after adding an assignment2 task under Assignment category and cs2113t module
      2. Expected: the program will prompt the user with message: SUCCESS!! Tag urgent is added.
    2. Wrong usage:

      1. Test case: addg urgent -m cs2113t -c Assignment -t non-exist-task
      2. Expected: the program will prompt the user with message: Sorry, the task is not found.
      3. Test case: addg urgent -t assignment2
      4. Expected: the program will promit the user with message: Sorry, unable to execute the command at the current directory. Either move to the appropriate directory level, or enter the full directory path.

3. Delete Command

Note
All the Delete Commands below are assumed to be executed at the root directory.
And user has only added a module cs2113t, a task called assignment2 under the category Assignment, with a file called test.pdf, with a tag urgent
  1. Delete modules
    1. Correct usage:
      1. Test case: delm cs2113t
      2. Expected: the program will prompt the user with message: Confirm delete CS2113T Software Engineering & Object-Oriented Programming? and user enter y and hit enter, the program will prompt the user with message: SUCCESS!! Module(s) have been deleted.
    2. Wrong usage:
      1. Test case: delm cs1111
      2. Expected: the program will prompt the user with message: Sorry. No modules found.
  2. Delete category
    1. Correct usage:
      1. Test case: delc Assignment -m cs2113t
      2. Expected: the program will prompt the user with message: Confirm delete Assignment? and user enter y and hit enter, the program will prompt the user with message: SUCCESS!! Category(s) have been deleted.
    2. Wrong usage:
      1. Test case: delc Project -m cs2113t
      2. Expected: the program will prompt the user with message: Sorry. No categories found.
  3. Delete task
    1. Correct usage:
      1. Test case: delt assignment2 -m cs2113t -c Assignment
      2. Expected: the program will prompt the user with message: Confirm delete assignment2? and user enter y and hit enter, the program will prompt the user with message: SUCCESS!! Task(s) have been deleted.
    2. Wrong usage:
      1. Test case: delt non-exist-task
      2. Expected: the program will prompt the use with message: Sorry. No tasks found.
  4. Delete file
    1. Correct usage:
      1. Test case: delf test.pdf -m cs2113t -c Assignment -t assignment2
      2. Expected: Expected: the program will prompt the user with message: Confirm delete test.pdf? and user enter y and hit enter, the program will prompt the user with message: SUCCESS!! Files(s) have been deleted.
    2. Wrong usage:
      1. Test case: delf non-exist.pdf -m cs2113t -c Assignment -t assignment2
      2. Expected: the program will prompt the user with message: Sorry. No files found.
  5. Delete tag
    1. Correct usage:
      1. Test case: delg urgent -m cs2113t -c Assignment -t assignment2
      2. Expected: the program will prompt the user with message: Confirm delete tag urgent of the task assignment2? and user enter y or yes, the program will prompt the user with message: SUCCESS!! Tag(s) have been deleted.
      3. Test case: delg
      4. Expected: the program will prompt the user with message: Confirm delete tag urgent of the task assignment2? and user enter n or no, the program will prompt the user with message: The deletion is aborted
    2. Wrong usage:
      1. Test case: delg non-exist-tag -m cs2113t -c Assignment -t assignment2
      2. Expected: the program will prompt the user with message: Sorry. No tasks with the tag found.

4. List Command

Note
All the List Commands below are assumed to be executed at the root directory.
And user has only added a module cs2113t, a task called assignment2 under the category Assignment, with a file called test.pdf, with a tag urgent
  1. List modules

    1. Test case: lsm

    2. Expected: the program display a table containing all the modules added by the user as shown below:

Back To Top

list file

  1. List tags

    1. Test case: lsg -m cs2113t -c Assignment -t assignment2

    2. Expected: the program display a table containing all the tags of the task assignment2 under module cs2113t and category Assignment added by the user as shown below:

list tag

  1. Correct Usage:
    1. Test case: enter cd cs2113t
    2. Expected: the program prompt will be changed to root / CS2113T : from root :
  2. Wrong Usage:
    1. Test case: enter cd ..
    2. Expected: the program prompt the user with message: Unable to traverse further.

5. Info Command

Note
For Info Command below are assumed to be executed at the root directory.
And user has added a module cs2113t
  1. Test case: enter info

  2. Expected: the program will display the information about the current directory to the user as shown below:

info

6. Open File Command

Note
All the List Commands below are assumed to be executed at the root directory.
And user has only added a module cs2113t, a task called assignment2 under the category Assignment, with a file called test.pdf
  1. Test case: enter open test.pdf -m cs2113t -c Assignment -t assignment2
  2. Expected: test.pdf will be opened automatically using the default pdf application.

Back To Top



Contact Us

If you have any further inquiries, or if you found any bugs while running or testing the Nuke application, feel free to contact us at:

Facebook             Gmail             Yahoo! Mail


We are currently still at the development stage of the Nuke application. Any feedback you give is welcomed as they can help us to improve Nuke even further! 😄


Back To Top