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
interfacewith the same name as the Component. - exposes its functionality using a concrete
{Component Name}Managerclass (which implements the corresponding APIinterfacementioned 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
Logiccomponent. - Listens for changes to
Modeldata so that the UI can be updated with the modified data.
Logic component

API :
Logic.java
-
Logicuses theWanderlustParserclass to parse the user command. - This results in a
Commandobject 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
CommandResultobject which is passed back to theUi. - In addition, the
CommandResultobject can also instruct theUito 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
UserPrefobject 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
UserPrefobjects 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
EditActivityCommandEditAccommodationCommandEditFriendCommandEditTravelPlanCommand
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 frameimplementation, the image below contains further details from theexecutereference 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 TravelPlans/TravelPlanObjects. 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 TravelPlanObjects 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
AddTravelPlanObjectCommandclass.- 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 TravelPlans/TravelPlanObjects. 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
DeleteTravelPlanObjectCommandclass.- 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
11or 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_dateandend_date -
Activity: Include
name,cost,location,datetime,importance -
Accommodation: Include
name,location,cost,startdateandenddateto it -
Friend: Contains information about a given friend
name,mobile numberandpassport number -
Directory: The two possible directories are
travelplan,wishlist -
Navigate: Use the
gotocommand to move between directories -
View: Use the
showcommand 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
friendas an example.a. Prerequisites: Show all friends using the
show -friendcommand. 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
friendas 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
xrefers to a valid index
-
Editing an activity/accommodation/friend while all activities/accommodation/friends are being shown. We will use
activityas an example.a. Test case:
edit -activity x i/4
Expected: Edit activity at specified indexx. Activity selected has updated importance of4Details 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 TripDetails 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
accommodationas 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 -accommodationwhile in wishlist.
Expected:showcommand 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
yrefers to keyword provided by user - Use the
showcommand to view back the unfiltered list.
-
Finding an activity/accommodation/friend while in a travel plan directory. We will use
activityas an example.a. Prerequisites: Show list of activity using
show -activitycommand. 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
wishlistdirectory.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
travelplanorwishlistdirectory.a. Test case:
goto -travelplan x(where x is a valid index)
Expected: Navigates to thetravelplanat specified indexx. Details of thetravelplanis shown in the status message.b. Test case:
goto -wishlist(where x is a valid index)
Expected: Navigates to thewishlist. Details ofwishlistis 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
travelplandirectory. We will useaccommodationas an example.a. Prerequisites: Currently in a
travelplandirectory.b. Test case:
sort -accommodation cost
Expected: Tab switches toaccommodationtab and returns a sorted list ofaccommodationin the order of decreasing cost.c. Test case:
sort -accommodation mobile
Expected:mobileis 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
wishlistdirectory.a. Prerequisites: Currently in a
wishlistdirectory.b. Test case:
sort -activity datetime
Expected:wishlistreturns a sorted list ofactivitiesin the order of increasing date and time.c. Test case:
sort -activity mobile
Expected:mobileis not a valid sort keyword foractivity. Error details shown in the status message.d. Test case:
sort -accommodation name
Expected:nameis 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
wishlistto the specifictravelplandirectory.- Note
xrefers to the index of the activity in thewishlist. - Note
yrefers to the index of thetravelplan.
a. Prerequisites: Currently in a
wishlistdirectory.b. Test case:
copy x y
Expected:activityat indexxin thewishlistis copied to thetravelplanat indexy.c. Test case:
copy x y(Wherexis 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(Whereyis 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 atravelplandirectory). Expected: Invalid command call attravelplandirectory.Copycan only be called inwishlistdirectory. 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
wishlistto the specifictravelplandirectory. The activity will be deleted from thewishlist.- Note
xrefers to the index of the activity in thewishlist. - Note
yrefers to the index of thetravelplan.
a. Prerequisites: Currently in a
wishlistdirectory.b. Test case:
move x y
Expected:activityat indexxin thewishlistis copied to thetravelplanat indexy.c. Test case:
move x y(Wherexis 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(Whereyis 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 atravelplandirectory). Expected: Invalid command call attravelplandirectory.Copycan only be called inwishlistdirectory. 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 travelplans 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.