Developer Guide
- Introduction
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Appendix: Effort
Introduction
Purpose
This document is written to describe the architecture and software design decisions for the desktop application, wanderlust.
Scope
The goal of this document is to cover the high-level system architecture and design. It will also cover the implementation of each feature in wanderlust.
Audience
The intended audience is any person who is looking to understand the system architecture and design of wanderlust.
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Main
has two classes called Main
and 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 methods where necessary.
Commons
represents a collection of classes used by multiple other components.
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 concrete
{Component Name}Manager
class (which implements the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component (see the class diagram given below) defines its API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class which implements the Logic
interface.
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 -activity 1
.
The sections below give more details of each component.
UI component
API :
Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, TravelPlannerPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
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.
Logic component
API :
Logic.java
-
Logic
uses theWanderlustParser
class to parse the user command. - This results in a
Command
object which is executed by theLogicManager
. - The command execution can affect the
Model
(e.g. adding a travel plan). - The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. - In addition, the
CommandResult
object can also instruct theUi
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 -activity 1")
API call.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Model component
API : Model.java
The Model
,
- stores a
UserPref
object that represents the user’s preferences. - stores the travel planner data.
- exposes unmodifiable
ObservableList<TravelPlan>
,ObservableList<Activity>
,ObservableList<Accommodation>
,ObservableList<Friend>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - does not depend on any of the other three components.
Storage component
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save the travel planner data in json format and read it back.
Common classes
Classes used by multiple components are in the seedu.address.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Changing Directory
Implementation
Wanderlust’s Ui supports navigating to different travel plans or wishlist so that users can view their desired
travel plan or wishlist easily. Starting up Wanderlust will show the default view of a wishlist and users
can use the goto
command to navigate to their desired directory.
TravelPlannerPanel
, TravelPlanPanel
and TravelPlanObjectListPanel
provide the core components for the display of
Wanderlust. When we are in the directory of travelplan or wishlist, MainWindow
renders all 3 of the above
components. TravelPlannerPanel
highlights the directory we are currently in, TravelPlanPanel
displays the name
of the
directory and if it is a travelplan, it will show the date
of the travelplan as well. Lastly, TravelPlanObjectListPanel
displays the respective activity
, accommodation
and friend
list in the UI of a particular directory. Do note that
wishlist
do not contain any accommodation
or friend
list. (The UI will not display any list)
Both TravelPlannerPanel
and TravelPlanObjectListPanel
make use of JavaFX’s ListView
to display the list of travelplan
or activity
/accommodation
/friend
respectively.
TravelPlannerPanel
utilizes JavaFX’s Label
to display the name
of the directory.
TravelPlanObjectListPanel
utilizes TabPane
and Tab
to display the different activity
/accommodation
/friend
tabs
respectively.
The class diagram below shows the relevant classes involved:
Navigating between directories
MainWindow
and CommandResult
facilitates the navigation between directories.
Firstly, MainWindow#fillInnerParts()
initializes an OberservableDirectory
which listens to any directory changes.
MainWindow#executeCommand()
is then called when user enters a goto
command into the application. MainWindow#executeCommand()
initializes all changes to what is displayed by the UI by calling Logic#execute()
which returns a CommandResult
.
From Logic#execute()
, MainWindow#handleDirectoryChange()
will navigate the current directory to the one input by the user, changing the
UI to view the new directory. From CommandResult
, the ResultDisplay
Ui will then output a text specifying which directory
has been navigated to.
The activity diagram below illustrates the flow of execution when the UI decides which directory to view:
Below is a sequence diagram that shows a scenario whereby the UI navigates to a specified travelplan
in Wanderlust
:
Design Consideration:
Aspect: How navigation between directory works
-
Alternative 1 (Current Choice): Initializing an observable directory in Wanderlust.
- Pros: Main Window will always be listen to any changes in directory, allowing UI to switch fast
- Cons: More work has to be done to sync up the UI with the model as we have to create an ObservableDirectory class and link to the model manager.
-
Alternative 2: Passing the Directory as a parameter in CommandResult method
- Pros: Easy to implement since we just have to return a new CommandResult which has an additional parameter of Directory.
- Cons: Break the abstraction layer as Commands (Logic) should not have to be aware of how the Model is working.
Editing Information
Implementation
The proposed editing mechanism is facilitated by EditDescriptor
, Index
and EditCommand
which extends Command
.
Editing can be done to travelplan objects such as Friend
, Accommodation
and Activity
or to TravelPlan
.
EditCommand
uses Index
to identify the object to be modified.
Index
provides standardisation between the components to refer to a specific travel plan object or travelplan within a list.
EditCommand
uses EditDescriptor
to create an edited object.
EditDescriptor
provides method buildFromSource(source)
to store and access edited fields specified within the user input.
Each object has a specific set of valid fields that can be modified.
-
Activity
: Name, Importance, Cost, DateTime, Location -
Accommodation
: Name, StartDate, EndDate, Location, Cost -
Friend
: Name, Passport, Mobile -
TravelPlan
: Name, StartDate, EndDate
EditCommand must have at least one field that is edited. Any fields that are invalid will throw an error.
Hence, child classes of EditCommand accounts for editing valid types of field. Each of the following classes extends EditCommand
EditActivityCommand
EditAccommodationCommand
EditFriendCommand
EditTravelPlanCommand
EditCommand
accounts for duplicated objects.
Activity
contain duplicates when two instances have the same name.
Friend
contain duplicates when two instances have the same passport number.
Accommodation
contains duplicates when two instances have the same name, startDate and endDate
TravelPlan
contains duplicates when two instances have the same name
When the editing of an object results in a duplicated edited object within travelplan list or travelplan object list, an error will be thrown.
Given below is the class diagram showing relevant classes involved
Editing a TravelPlan or TravelPlanObject
Given below is an example usage scenario and how the edit mechanism behaves at each step.
Below is a sequence diagram that shows a scenario whereby the user edits a specified activity in Wanderlust
The TravelPlan Object or TravelPlan by calling Logic#execute()
which returns a CommandResult
. From CommandResult
, the Ui will then
show a message about the successful edited object.
- Note: Due to limitation of PlantUML which do not have an
sd reference frame
implementation, the image below contains further details from theexecute
reference frame from the above sequence diagram.
Design Consideration
Aspect: How edit executes
-
Alternative 1 (Current Choice): Editing in the current travelplan directory
- Pros: Only require the index shown on the UI to identify the travelplan object to be edited
- Cons: More work has to be done to sync the retrieval of lists of travel plan object that corresponds to the current travelplan directory
-
Alternative 2: Require the user to switch travel plan object tabs within the travelplan to edit the specified travelplan object
- Pros: User will not require to specify the type of travelplan object to be edited
- Cons: Still require user to specify editing of a travelplan object or travelplan
Adding a TravelPlan or TravelPlanObject
Implementation
Wanderlust’s Ui allows users to add a TravelPlan
to the TravelPlanner
, an Activity
to the Wishlist
and a TravelPlanObject
to the TravelPlan
in the current directory.
MainWindow#executeCommand()
is called when the user enters a add
command into the application. MainWindow#executeCommand()
adds the TravelPlan/TravelPlanObject by calling Logic#execute()
which returns a CommandResult
. Logic#execute()
also sets the
the Directory
of the ObservableDirectory
to the updated Directory
after adding the TravelPlan/TravelPlanObject so the Ui displays
the updated list of TravelPlan
s/TravelPlanObject
s. From CommandResult
, the ResultDisplay
Ui will then output a text confirming
to the user that the command was successfully executed.
The activity diagram below shows a scenario whereby a user adds inputs an add command:
The sequence diagram below shows a scenario whereby a user adds an Activity
to the TravelPlan
/Wishlist
in the current directory:
Design Consideration:
Aspect: How to add TravelPlanObject
s to the TravelPlan
in the current Directory
-
Alternative 1 (Current Choice): Use individual add commands for each sub-class of
TravelPlanObject
.- Pros: Greater abstraction and a more logical implementation since there is a command for each sub-class.
- Cons: Greater repetition of code.
-
Alternative 2: Using a
AddTravelPlanObjectCommand
class.- Pros: Lesser repetition of code.
- Cons: Lesser abstraction.
Deleting a TravelPlan or TravelPlanObject
Implementation
Wanderlust’s Ui allows users to delete a TravelPlan
from the TravelPlanner
, an Activity
from the Wishlist
and a TravelPlanObject
from the TravelPlan
in the current directory.
MainWindow#executeCommand()
is called when the user enters a delete
command into the application. MainWindow#executeCommand()
deletes the TravelPlan/TravelPlanObject by calling Logic#execute()
which returns a CommandResult
. Logic#execute()
also sets the
the Directory
of the ObservableDirectory
to the updated Directory
after deleting the TravelPlan/TravelPlanObject so the Ui displays
the updated list of TravelPlan
s/TravelPlanObject
s. From CommandResult
, the ResultDisplay
Ui will then output a text confirming
to the user that the delete
command was successfully executed.
The activity diagram below shows a scenario whereby a user inputs the delete
command:
The sequence diagram of the delete
command has been shown above under the Logic Component of the developer guide.
Design Consideration:
Aspect: How to delete a TravelPlanObject
from the TravelPlan
in the current Directory
-
Alternative 1 (Current Choice): Use individual delete commands for each sub-class of
TravelPlanObject
.- Pros: Greater abstraction and a more logical implementation since there is a command for each sub-class.
- Cons: Greater repetition of code.
-
Alternative 2: Using a
DeleteTravelPlanObjectCommand
class.- Pros: Lesser repetition of code.
- Cons: Lesser abstraction and the logic will be reliant on one class.
Copy feature
Implementation
The copy mechanism supports copying an activity
from Wishlist
to a specific TravelPlan
. It is facilitated by the
add mechanism, except activities can be added to any TravelPlan
in the TravelPlanner
, referenced by their index
(travel plan index). The copy mechanism adds a deep copy of the activity in Wishlist
to the specified TravelPlan
,
not the same instance. Thus, if any activity was edited in one directory, it should not affect all other copies.
filteredWishlist
in Model
. This means, even if the find
command is used to filter the activities in the
wishlist, the indexes in the filteredWishlist
will be updated accordingly (and so will the Ui). Hence, as long as the
user uses the index as displayed in the Ui, the correct activity will be referenced.
The following sequence diagram shows how the copy operation works:
CopyCommandParser
and
CopyCommand
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of
diagram.
execute()
method (after parsing) is zero-based.
The following activity diagram summarizes what happens when a user executes the copy
command:
Design consideration:
Aspect: How to duplicate activity (deep/shallow copy)
-
Alternative 1 (Current Choice): Using a deep copy.
- Pros: More flexibility to have different variations of the activity in different directories (e.g. different dates/times, etc).
- Cons: Each instance is not synced with the rest. Users have to update each copy separately if they wish to do so. However, there is flexibility to extend other commands (e.g. Edit command) to update all deep copies of the same activity.
-
Alternative 2: Using a shallow copy.
- Pros: Only one instance of each activity means users can update all copies of the activity at once.
- Cons: Less flexibility to change a copied activity without affecting other copies.
-
Alternative 3: Have variations of the copy command to allow both deep/shallow copy.
- Pros: Best of both worlds. Allows for flexibility and convenience at the same time.
- Cons: Harder to implement. Users need a way to differentiate deep/shallow copies to avoid unintentionally editing a shallow copy. Potentially more edge cases to think about and handle.
Move Feature
Implementation
The move mechanism makes use of both the copy and delete mechanism.
Find Feature
Implementation
Current implementation of Find feature is facilitated by NameContainsKeywordsPredicate
which implements
Predicate<Nameable>
and has the test method overriden with a custom implementations.
The NameContainsKeywordsPredicate#test(Nameable)
is as follows:
- loops through the keywords (of type
List<String>
) and return true if there is any match with theNameable
Nameable
provides the following operation:
-
Nameable#getName()
- Return the name attribute of aTravelPlanObject
NameContainsKeywordsPredicate
will be passed to Model#updateFilteredXYZList(Predicate)
(updateFilteredActivityList
, etc.). The filtered list will then be updated according to the given Predicate
and
automatically reflected on the Ui.
The class diagram shows the relevant classes involved:
The following sequence diagram shows how the find operation works:
The following activity diagram summarizes what happens when a user executes the find command:
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- Has a need to store their travel plans in an organised manner
- Has a need to store activities that they may visit as a wishlist
- Prefers desktop apps over other types
- Can type fast
- Prefers typing to mouse interactions
- Is reasonably comfortable using CLI apps
Value proposition:
- Manage travel plans faster than using a typical mouse/GUI driven app. Removes the need for a physical travel planner. Increase the motivation to plan travelling by making planning easier and interactive.
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 | read the user guide | be familiar with the usages and features |
* * * |
user | save activities in a wishlist | use it for future travel plans |
* * * |
user | add items to a travel plan | note down important items related to my travel plan |
* * * |
user | delete an item | remove unwanted items |
* * * |
user | modify an item | edit any last minute changes |
* * * |
frequent user | have a list of items | easily see my travel plans |
* * * |
user | switch between travel plans | easily retrieve each travel plan |
* * |
user | input accommodation details | easily remember where I am going to stay |
* * |
user | input cost of activity | track the price of each activities easily |
* * |
user | input timing to an activity | plan a schedule for my travel plan |
* * |
user | record particulars of my friends travelling with me | make group reservations/ bookings more convenient. |
* * |
user | sort items | view my items in a preferred manner |
* * |
user | create priority levels for activities | rank the importance of each activity |
* |
user | have a feature to search | find and filter my desired items efficiently |
* |
user | have a move and copy feature | move/copy activities in my wishlist to my travel plan easily |
* |
user | be able to switch tabs | view my activities, accommodation and friends easily |
Use cases
(For all use cases below, the System is Wanderlust
and Actor is the user
, unless otherwise specified)
Use case: UC01 - Navigate to a specific travel plan
MSS
- User requests to navigate to a specific travel plan.
-
Wanderlust navigates to the travel plan that user requested.
Use case ends.
Extensions
- 1a. The specific travel plan doesn’t exist.
-
1a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC02 - Navigate to the wishlist
MSS
- User requests to navigate to the wishlist.
-
Wanderlust navigates to wishlist.
Use case ends.
Extensions
- 1a. User is already on wishlist.
- 1a1. Wanderlust remains on wishlist.
Use case ends.
Use case: UC03 - Add a travel plan
MSS
- User requests to add a travel plan
-
Wanderlust creates the newly travel plan and directs user to the new travel plan.
Use case ends.
Extensions
- 1a. The input command format is invalid.
-
1a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC04 - Add an activity
MSS
- User navigates to a specific travel plan (UC1).
- User requests to add an activity.
-
Wanderlust shows the added activities in the current directory.
Use case ends.
Extensions
-
1a. User navigates to the wishlist (UC2).
Use case resumes at step 2.
-
2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC05 - Add an accommodation
MSS
- User navigates to a specific travel plan (UC1).
- User requests to add an accommodation.
-
Wanderlust shows the added accommodation in the current travel plan.
Use case ends.
Extensions
- 1a. User is at the wishlist.
- 1a1. User requests to add accommodation.
- 1a2. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC06 - Add a friend
MSS
- User navigates to a specific travel plan (UC1).
- User requests to add a friend.
-
Wanderlust shows the added friend in the current travel plan.
Use case ends.
Extensions
- 1a. User is at the wishlist.
- 1a1. User requests to add a friend.
- 1a2. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC07 - Delete a travel plan
MSS
- User requests to delete a travel plan.
-
Wanderlust shows that the travel plan has been deleted.
Use case ends.
Extensions
- 1a. The input command format is invalid.
-
1a1. Wanderlust shows an error message.
Use case ends.
-
- 1b. The travel plan specified does not exist.
-
1b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC08 - Delete an activity
MSS
- User navigates to a specific travel plan (UC1).
- User requests to delete an activity.
-
Wanderlust shows that the activity has been deleted.
Use case ends.
Extensions
-
1a. User navigates to the wishlist (UC2).
Use case resumes at step 2.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
- 2b. The activity specified does not exist.
-
2b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC09 - Delete an accommodation
MSS
- User navigates to a specific travel plan (UC1).
- User requests to delete an accommodation.
-
Wanderlust shows that the accommodation has been deleted.
Use case ends.
Extensions
- 1a. User is at the wishlist.
- 1a1. User requests to delete accommodation.
- 1a2. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
- 2b. The accommodation specified does not exist.
-
2b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC10 - Delete a friend
MSS
- User navigates to a specific travel plan (UC1).
- User requests to delete a friend.
-
Wanderlust shows that the friend has been deleted.
Use case ends.
Extensions
- 1a. User is at the wishlist.
- 1a1. User requests to delete a friend.
- 1a2. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
- 2b. The friend specified does not exist.
-
2b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC11 - Edit a travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to edit travel plan.
-
Wanderlust shows that the travel plan has been edited.
Use case ends.
Extensions
-
1a. User is at the wishlist.
Use case resumes at step 2.
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
Use case ends.
- 2b. The travel plan specified does not exist.
- 2b1. Wanderlust shows an error message.
Use case ends.
Use case: UC12 - Edit an activity
MSS
- User navigates to a specific travel plan (UC1).
- User requests to edit an activity.
-
Wanderlust shows that the activity has been edited.
Use case ends.
Extensions
-
1a. User navigates to the wishlist (UC2)..
Use case resumes at step 2.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
- 2b. The activity specified does not exist.
-
2b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC13 - Edit an accommodation
MSS
- User navigates to a specific travel plan (UC1).
- User requests to edit an accommodation.
-
Wanderlust shows that the accommodation has been edited.
Use case ends.
Extensions
- 1a. User is at the wishlist.
- 1a1. User requests to edit an accommodation.
- 1a2. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
- 2b. The accommodation specified does not exist.
-
2b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC14 - Edit a friend
MSS
- User navigates to a specific travel plan (UC1).
- User requests to edit a friend.
-
Wanderlust shows that the friend has been edited.
Use case ends.
Extensions
- 1a. User is at the wishlist.
- 1a1. User requests to edit a friend.
- 1a2. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
- 2b. The friend specified does not exist.
-
2b1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC15 - View activities
MSS
- User navigates to a specific travel plan (UC1).
- User requests to view activities.
-
Wanderlust shows the list of activities.
Use case ends.
Extensions
-
1a. User navigates to the wishlist (UC2).
Use case resumes at step 2.
-
2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC16 - View friends in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to view friends.
-
Wanderlust shows the list of friends.
Use case ends.
Extensions
- 2a. The input command format is invalid.
-
2a1. Wanderlust shows an error message.
Use case ends.
-
Use case: UC17 - View accommodations in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to view accommodation.
-
Wanderlust shows the list of accommodation.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
Use case ends.
- 2a. The input command format is invalid.
Use case: UC18 - Clear the travel planner
MSS
- User requests to clear the travel planner.
-
Wanderlust clears the travel planner.
Use case ends.
Use case: UC19 - Sort activity list in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to sort activity list by cost.
-
Wanderlust returns sorted list of activities by decreasing cost.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
Use case ends.
Use case: UC20 - Sort accommodation list in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to sort accommodation list by date.
-
Wanderlust returns sorted list of accommodation by date in chronological order.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
-
2b. User is still in wishlist. *2b1. Wanderlust shows an error message.
Use case ends.
Use case: UC21 - Sort friend list in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to sort friend list by name.
-
Wanderlust returns sorted list of name in alphabetical order.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
-
2b. User is still in wishlist. *2b1. Wanderlust shows an error message.
Use case ends.
Use case: UC22 - Find activity in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to find activities according to keyword.
-
Wanderlust returns a filtered list of activities that contain the keyword.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
- 2b. Activity list do not contain the keyword input by user.
- 2b1. Wanderlust returns an empty list.
Use case ends.
Use case: UC23 - Find accommodation in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to find accommodation according to keyword.
-
Wanderlust returns a filtered list of accommodation that contain the keyword.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
- 2b. Accommodation list do not contain the keyword input by user.
- 2b1. Wanderlust returns an empty list.
Use case ends.
Use case: UC24 - Find friend in travel plan
MSS
- User navigates to a specific travel plan (UC1).
- User requests to find friends according to keyword.
-
Wanderlust returns a filtered list of friends that contain the keyword.
Use case ends.
Extensions
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
- 2b. friend list do not contain the keyword input by user.
- 2b1. Wanderlust returns an empty list.
Use case ends.
Use case: UC25 - Move activity from wishlist to travel plan
MSS
- User is at wishlist directory.
- User requests to move an activity from wishlist to his desired travel plan.
-
Wanderlust transfers the activity to the desired travel plan, deleting the specific activity from the wishlist.
Use case ends.
Extensions
- 1a. User is at a travel plan.
- 1a1. Wanderlust shows an error message when user request to move an activity in a travel plan.
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
Use case ends.
Use case: UC26 - Copy activity from wishlist to travel plan
MSS
- User is at wishlist directory.
- User requests to copy an activity from wishlist to his desired travel plan.
-
Wanderlust copies the activity to the desired travel plan.
Use case ends.
Extensions
- 1a. User is at a travel plan.
- 1a1. Wanderlust shows an error message when user request to copy an activity in a travel plan.
- 2a. The input command format is invalid.
- 2a1. Wanderlust shows an error message.
Use case ends.
Use case: UC27 - Help
MSS
- User requests for help to input specific commands.
-
Wanderlust shows a pop-up window, containing a link to Wanderlust’s user guide for help.
Use case ends.
Use case: UC28 - Exit
MSS
- User requests to exit Wanderlust.
-
Wanderlust shuts down.
Use case ends.
Non-Functional Requirements
- Should work on any mainstream OS_ as long as it has Java
11
or above installed. - The travel planner should be able to hold up to 1000 travel plans without a noticeable sluggishness in performance for typical usage.
- Should be able to respond to user commands within 1 second.
- 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.
- Should be a single-user product.
- Users familiar with JSON should be able to read and edit the storage file.
- Should work without internet connection.
- Should not crash when data is given in compatible formats.
- The app should be accessible via the downloaded JAR file without any other installations needed.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Wishlist: A list of potential activities
-
Travel plan: A list of accommodations and activities in a specified location that include
name
,start_date
andend_date
-
Activity: Include
name
,cost
,location
,datetime
,importance
-
Accommodation: Include
name
,location
,cost
,startdate
andenddate
to it -
Friend: Contains information about a given friend
name
,mobile number
andpassport number
-
Directory: The two possible directories are
travelplan
,wishlist
-
Navigate: Use the
goto
command to move between directories -
View: Use the
show
command to provide a list of specified travel plan object
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
a. Download the jar file and copy into an empty folder
b. Run jar file in command prompt and enter
java -jar wanderlust.jar
: Expected: Shows the GUI with a set of sample data. The window size may not be optimum. -
Saving window preferences
a. Resize the window to an optimum size. Move the window to a different location. Close the window.
b. Re-launch the app by running the jar file in the command prompt and enter
java -jar wanderlust.jar
.
Expected: The most recent window size and location is retained.
Delete
-
Deleting an activity/accommodation/friend while all activities/accommodation/friends are being shown. We will use
friend
as an example.a. Prerequisites: Show all friends using the
show -friend
command. Multiple Friends in the list.b. Test case:
delete -friend 1
Expected: First Friend is deleted from the friend list. Details of the deleted friend shown in the status message.c. Test case:
delete -friend 0
Expected: No Friend is deleted. Error details shown in the status message.d. Other incorrect delete commands to try:
delete
,delete -friend x
,...
(where x is larger than the list size)
Expected: Similar to previous. -
Deleting a travelplan.
a. Test case:
delete -travelplan 1
Expected: First travel plan is deleted from the travel plan list. Details of the deleted travel plan shown in the status message.c. Test case:
delete -travelplan 0
Expected: No travel plan is deleted. Error details shown in the status message.d. Other incorrect delete commands to try:
delete
,delete -travelplan x
,...
(where x is larger than the list size)
Expected: Similar to previous.
Add
-
Adding an activity/accommodation/friend while all activities/accommodation/friends are being shown. We will use
friend
as an example.a. Prerequisites: Navigate to a valid directory using
goto -travelplan x
(where x is a valid index)b. Test case:
add -friend n/Tom p/E1234567X m/81234567
Expected: New Friend is added to the friend list. Details of the added friend shown in the status message.c. Test case:
add n/Jerry p/E1234567M m/81234561
Expected: Add object type is not specified. No Friend is added. Error details shown in the status message.d. Test case:
add -friend n/Spark p/E1234567A m/81234568 i/2
Expected: Importance parameter is not valid for Friend. No Friend is added. Error details shown in the status message.e. Other incorrect add commands to try:
add
,add -friend n/Harry
Expected: Error message is thrown. -
Adding a travel plan.
a. Test case:
add -travelplan n/Europe Trip sd/2021-01-10 ed/2021-02-10
Expected: New travel plan is add to the travel plan list. Details of the travel plan shown in the status message.b. Test case:
add n/Europe Trip sd/2021-01-10 ed/2021-02-10
Expected: Add object type is not specified. No travel plan is added. Error details shown in the status message.c. Test case:
add n/Europe Trip sd/2021-01-10 ed/2021-02-10 c/1000
Expected: Cost parameter is not valid for travel plan. No trave plan is added. Error details shown in the status message.d. Other incorrect add commands to try:
add
,add -travelplan n/Europe
Expected: Similar to previous.
Edit
- Note
x
refers to a valid index
-
Editing an activity/accommodation/friend while all activities/accommodation/friends are being shown. We will use
activity
as an example.a. Test case:
edit -activity x i/4
Expected: Edit activity at specified indexx
. Activity selected has updated importance of4
Details of the activity is shown in the status message.b. Test case:
edit -activity x p/E1234593P
Expected: Passport parameter is not valid for Activity. No Activity is edited. Error details shown in the status message.c. Test case:
edit x n/Ice Skating
Expected: Edit object type is not specified. No Activity is edited. Error details shown in the status message.d. Other incorrect add commands to try:
edit -activity
Expected: Error message is thrown. -
Editing a travel plan
a. Test case:
edit -travelplan x n/New Trip
Expected: Edit the travel plan at specified indexx
. Travel plan selected has updated name ofnew Trip
Details of the travel plan is shown in the status message.b. Test case:
edit -travelplan x c/123
Expected: Cost parameter is not valid for travel plan. No travel plan is edited. Error details shown in the status message.c. Test case:
edit x n/Europe
Expected: Edit object type is not specified. No travel plan is edited. Error details shown in the status message.d. Other incorrect add commands to try:
edit -travelplan
Expected: Error message is thrown.
Show
-
Showing an activity/accommodation/friend while in a travel plan directory. We will use
accommodation
as an example.a. Prerequisites: Currently in a travel plan directory.
b. Test case:
show -accommodation
Expected: Show the accommodation list in the accommodation tab.c. Test case:
show -accommodation 1
Expected: Invalid command format. Error details shown in the status message.d. Test case:
show -accommodation
while in wishlist.
Expected:show
command is not valid in wishlist. Error details shown in the status message.e. Other incorrect show commands to try:
show -accommodation c/20
Expected: Error message is thrown.
Find
- Note
y
refers to keyword provided by user - Use the
show
command to view back the unfiltered list.
-
Finding an activity/accommodation/friend while in a travel plan directory. We will use
activity
as an example.a. Prerequisites: Show list of activity using
show -activity
command. Currently in a travel plan directory.b. Test case:
find -activity y
Expected: Find all activities that contain y. Activity tab will be updated and display the activites that matches the keyword(s)y
.c. Test case:
find -activity
Expected: Cannot have empty field for the keyword. Error details shown in the status message.c. Other incorrect add commands to try:
find
,find -travelplan
Expected: Invalid command format. Error message is thrown. -
Finding an activity while in a wishlist.
a. Prerequisites: Currently in the
wishlist
directory.b. Test case:
find -activity y
Expected: Find all activities that contain y. Activity tab will be updated and display the activites that matches the keyword(s)y
.c. Test case:
find -activity
Expected: Cannot have empty field for the keyword. Error details shown in the status message.d. Test case:
find -accommodation y
Expected: Accommodation is not valid in wishlist. Error details shown in the status message.c. Other incorrect add commands to try:
find
,find -friend y
Expected: Invalid command. Error message is thrown.
Goto
-
Navigate to a
travelplan
orwishlist
directory.a. Test case:
goto -travelplan x
(where x is a valid index)
Expected: Navigates to thetravelplan
at specified indexx
. Details of thetravelplan
is shown in the status message.b. Test case:
goto -wishlist
(where x is a valid index)
Expected: Navigates to thewishlist
. Details ofwishlist
is shown in the status message.c. Test case:
goto -travel plan 0
Expected: Index is invalid, need to start from 1. Directory remains the same. Error details shown in the status message.d. Test case:
goto -wishlist 1
Expected: Index not required forwishlist
. Directory remains the same. Error details shown in the status message.e. Other incorrect add commands to try:
goto
,goto -random
Expected: Error message is thrown.
Sort
-
Sorting an activity/accommodation/friend list while in a
travelplan
directory. We will useaccommodation
as an example.a. Prerequisites: Currently in a
travelplan
directory.b. Test case:
sort -accommodation cost
Expected: Tab switches toaccommodation
tab and returns a sorted list ofaccommodation
in the order of decreasing cost.c. Test case:
sort -accommodation mobile
Expected:mobile
is not a valid sort keyword foraccommodation
. Error details shown in the status message.d. Other incorrect sort commands to try:
sort
,sort -accommdoation 1
Expected: Error message is thrown. -
Sorting an activity list in a
wishlist
directory.a. Prerequisites: Currently in a
wishlist
directory.b. Test case:
sort -activity datetime
Expected:wishlist
returns a sorted list ofactivities
in the order of increasing date and time.c. Test case:
sort -activity mobile
Expected:mobile
is not a valid sort keyword foractivity
. Error details shown in the status message.d. Test case:
sort -accommodation name
Expected:name
is not a valid sort keyword foractivity
. Error details shown in the status message.e. Other incorrect sort commands to try:
sort
,sort -friend name
Expected: Error message is thrown.
Copy
- Copy an activity from the
wishlist
to the specifictravelplan
directory.- Note
x
refers to the index of the activity in thewishlist
. - Note
y
refers to the index of thetravelplan
.
a. Prerequisites: Currently in a
wishlist
directory.b. Test case:
copy x y
Expected:activity
at indexx
in thewishlist
is copied to thetravelplan
at indexy
.c. Test case:
copy x y
(Wherex
is more than the size of the activity list in the `wishlist) Expected: Invalid index provided. Error details shown in the status message.c. Test case:
copy x y
(Wherey
is more than the total number of travel plans) Expected: Invalid index provided. Error details shown in the status message.d. Test case:
copy x y
(When in atravelplan
directory). Expected: Invalid command call attravelplan
directory.Copy
can only be called inwishlist
directory. Error details shown in the status message.e. Other incorrect copy commands to try:
copy
,copy x
,copy y
Expected: Error message is thrown. - Note
Move
- Move an activity from the
wishlist
to the specifictravelplan
directory. The activity will be deleted from thewishlist
.- Note
x
refers to the index of the activity in thewishlist
. - Note
y
refers to the index of thetravelplan
.
a. Prerequisites: Currently in a
wishlist
directory.b. Test case:
move x y
Expected:activity
at indexx
in thewishlist
is copied to thetravelplan
at indexy
.c. Test case:
move x y
(Wherex
is more than the size of the activity list in the `wishlist) Expected: Invalid index provided. Error details shown in the status message.c. Test case:
move x y
(Wherey
is more than the total number of travel plans) Expected: Invalid index provided. Error details shown in the status message.d. Test case:
move x y
(When in atravelplan
directory). Expected: Invalid command call attravelplan
directory.Copy
can only be called inwishlist
directory. Error details shown in the status message.e. Other incorrect copy commands to try:
move
,move x
,move y
Expected: Error message is thrown. - Note
Clear
-
Clear the entire data in wanderlust and returns an empty travel planner.
a. Test case:
clear
Expected: Returns an empty travel planner. Existing data is wiped.
Appendix: Effort
Model
The Model
of wanderlust is much more complex than AB3. In AB3, the model is only in charge of the Person class, which takes in simple attributes
relating to Person objects.
In wanderlust, each travel plan handles a total of 3 different objects, namely, Activity, Accommodation and Friend. Furthermore,
wanderlust also have an exclusive wishlist that keep track of Activity objects. Essentially, it is similar to one large model
handling 3 x AB3. Complex attributes such as Cost
is also implemented so that wanderlust can calculate the total cost of the travelplan
.
Furthermore, the attributes of the different classes have to interact with one another to ensure that they are cohesive.
For instance, we have to make sure any activty
/accommodation
date is within the range of the travelplan
’s date. The logic behind can be
implemented in many ways and we went through a variety of approaches to simplify the logic.
Lastly, the Model
of wanderlust support higher level features and commands such as sorting, moving and navigating to
different directories that were not present in AB3.
Logic
The complexity of Logic
was more advanced than AB3. wanderlust’s Logic
supports
many more commands compared to AB3, such as sort
, goto
, copy
, move
, show
commands. Existing commands from AB3 were also
enhanced to handle the complex Model
of wanderlust.
There was significant effort placed in creating the logic for _wanderlust. The Logic
of _wanderlust is responsible for
at least 3x the Logic
of AB3. It has to account for the logic of travelplan
, wishlist
, activity
, accommodation
and friend
whilst
AB3 handles Person
. Furthermore, additional logic was implemented to account for the navigation of directories and travel plans.
For example, ObservableDirectory
class was created to keep track of what directory the user is currently on so that the Ui
will be
able to display the correct travelplan
or wishlist
.
Additional efforts were also put into validating user input and ensuring that wanderlust’s parser can handle unexpected input smoothly.
Storage
The Storage
was extended to store more classes of wanderlust. activity
, accommodation
, and friend
objects have to be organised and
stored in a travelplan
, and all these data will be placed in a JSON file in an organised manner. Essentially, the JSON file will contain
data of various travelplan
s and a wishlist
, and each travelplan
will contain more data regarding activity
, accommodation
, and friend
,
with each travelplan
object storing its own attributes as well.
Furthermore, complex attributes such as wanderlustdate
and wanderlustdatetime
have to be stored in the JSON file in an approriate format.
Significant time and effort were put into discussing and planning the best way to represent each new attribute in the JSON file.
Ui
The Ui
component took us the most amount of time. We have to redesign the entire AB3 Ui to fit wanderlust design.
A lot of effort was placed in planning the structure of the Ui
so that our user interface will be user-friendly and appealing.
Furthermore, additional logic of navigating between travel plans and switching between the activity/accommodation/friend tabs was implemented
so that users can use the application smoothly. The logic of handling 3 different objects as opposed to just 1 in AB3
turned out to be far more complex than imagined, and we had to do multiple rounds of experimenting and refactoring to
work within certain constraints of JavaFX. One example is that JavaFX’s ListView does not accept wildcard-types, thus we
could not simply use ? extends TravelPlanObject
in the TravelPlanObjectPanel
. This led us to ultimately make use of tab panes
to handle the 3 TravelPlanObject types differently. We also spent a considerable amount of time in studying javafxml and css so that we are able to implement an
entirely new UI with icons and navigation options, making it a more interactive experience for the users as compared to the single page view of AB3’s Ui.
Overall
All in all, this project was a challenging one for the wanderlust team. We started off with many ideas and features that were seemed very appealing. However, we eventually decided that they were not suitable due to time constraints. In the first iteration, time and effort were placed in brainstorming and coming up with a concrete and feasible product. Throughout the weeks, we made consistent efforts to study the source code, modify existing features and create new features for wanderlust. There were high standards placed amongst us in ensuring that all of us put in time and effort in building wanderlust. Rigorous testing, trial and error were fundamental in the process so that we can deliver wanderlust within the timeline. Whilst wanderlust may not be the perfect travel planner application, this journey was a memorable one filled with teamwork and perseverance, and we are all proud of the end product.