By: Team Plan²travel      Since: Sep 2019      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

ArchitectureDiagram
Figure 1. Architecture Diagram

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

The .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide 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 method where necessary.

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

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

The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

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

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

Each of the four components

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

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

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

LogicClassDiagram
Figure 2. Class Diagram of the Logic Component

How the architecture components interact with each other

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

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, FeedbackDisplay, ContactListPanel, ActivityListPanel, AccomodationListPanel 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.

2.3. Logic component

LogicClassDiagram
Figure 5. Structure of the Logic Component

API : Logic.java

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

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

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

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

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

Given below is the Sequence Diagram for interactions within the Logic component for the execute("add activity n/Climb Fuji a/Mount Fuji") API call.

AddSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the add activity n/Climb Fuji a/Mount Fuji Command
The lifeline for AddCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.4. Model component

ModelClassDiagram
Figure 7. Structure of the Model Component

API : Model.java

The Model,

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

  • stores a ActivityManager, AccommodationManager, ContactManager and Itinerary that represents the managers for activity, accommodation, contact and day respectively.

  • exposes an unmodifiable ObservableList<Activity>, ObservableList<Accommodation>, ObservableList<Contact> and ObservableList<Day> 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.

2.5. Storage component

StorageUML
Figure 8. Structure of the Storage Component

API : Storage.java

The Storage component,

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

  • application data is split into 4 different components, Accommodation, Activity, Contact, Itinerary.

2.5.1. Accommodation Storage component

AccommodationStorageUML
Figure 9. Structure of Accommodation Storage component

The Accommodation Storage component,

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

  • as Tag is a field in Accommodation, similarly JsonAdaptedTag is a field within JsonAdaptedAccommodation. Hence the association as shown in the diagram above.

  • as Contact is a field in Accommodation, similarly JsonAdaptedContact is a field within JsonAdaptedAccommodation. Hence the association as shown in the diagram above.

2.5.2. Activity Storage component

ActivityStorageUML
Figure 10. Structure of Activity Storage component
  • can save Activity objects in json format and read it back.

  • as Tag is a field in Activity, similarly JsonAdaptedTag is a field within JsonAdaptedActivity. Hence the association as shown in the diagram above.

  • as Contact is a field in Activity, similarly JsonAdaptedContact is a field within JsonAdaptedActivity. Hence the association as shown in the diagram above.

2.5.3. Contact Storage component

ContactStorageUML
Figure 11. Structure of Contact Storage component
  • can save Contact objects in json format and read it back.

  • as Tag is a field in Contact, similarly JsonAdaptedTag is a field within JsonAdaptedContact. Hence the association as shown in the diagram above.

2.5.4. Itinerary Storage component

ItineraryStorageUML
Figure 12. Structure of Itinerary Storage component
  • can save Itinerary objects in json format and read it back.

  • as ActivityWithTime is a field in Day, similarly JsonAdaptedActivityWithTime is a field within JsonAdaptedDay. Hence the association as shown in the diagram above.

  • as Activity is a field in ActivityWithTime, similarly JsonAdaptedActivity is a field within JsonAdaptedActivityWithTime. Hence the association as shown in the diagram above.

2.6. Common classes

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

3. Implementation

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

3.1. Trip management

Plan²travel allows the user to create new trips, load and rename existing trips, make copies of existing trips and also clear existing trip information.

List of commands that helps with trip management:

  • new n/NAME  — Creates and loads a new empty trip with desired name

  • copyto n/NAME  — Creates and loads a copy of current trip using desired name

  • load n/NAME — Loads a saved trip with desired name

  • set n/NAME — Renames current trip to desired name

  • clear — Clears all current trip information except for name

3.1.1. Current Implementation

A trip (or trip plan) will have a name that is identical to the directory name which it represents. The directory will be accessible via the data/{Directory Name} directory path of the home folder which the plan2travel.jar is stored in.

For example, a trip named "Japan Trip" will represent a Japan Trip directory. This directory can be accessed using the data/Japan Trip directory path.

The directory will contain the accommodation.json, activity.json, contact.json and itinerary.json of the current saved trip.

The trip management mechanism is facilitated by UserPrefs where the desired directory path is stored internally as plannerFilePath.

Operations to access plannerFilePath are exposed in the Model interface as Model#getPlannerFilePath() and Model#setPlannerFilePath(Path) respectively.

Given below is the sequence diagram of how the load operation works:

LoadSequenceDiagram
Figure 13. Sequence diagram for load command
The lifeline for LoadCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

The sequence diagram above can be described by the following sequence of events:

  1. LoadCommand is executed

  2. LoadCommand updates the UserPrefs plannerFilePath and the Itinerary nameProperty

  3. LogicManager updates the respective file paths (that have been updated due to changes in plannerFilePath) in the Storage component

  4. LogicManger updates the respective lists in the Model component based on the new file paths

  5. LogicManager saves the respective lists in json format in directory designated by plannerFilePath through the Storage component

The following activity diagram summarizes what happens when a user executes a copyto command.

CopyToActivityDiagram
Figure 14. Activity diagram for copyto command

3.1.2. Design Considerations

Aspect: How the Logic component executes set

  • Current Choice: Deletes current directory before saving new directory containing previous json files

    • Pros:

      • Uses File#delete() which is platform-independent and helps in ensuring the stability of the application.

    • Cons:

      • May seem less intuitive. Deletion methods are used instead of renaming methods (which may be more appropriate given that set helps to rename the current directory).

      • Likely to be more costly in terms of execution as it involves deleting the previous directory and saving a new one.

  • Alternative: Rename current directory and avoid saving over the updated directory.

    • Pros:

      • Likely to be less costly in terms of execution as it does not involve deletion and saving of directories.

    • Cons:

      • Uses File#renameTo() which is platform-dependent and may contribute to a less stable application.

Aspect: How the commands execute based on Java API methods

  • Current Choice: Uses methods from File such as File#delete() and File#exists()

    • Pros:

      • Methods used do not throw an IOException and may help ensure the stability of the application.

    • Cons:

      • It may be difficult to diagnose issues that may arise.

  • Alternative: Uses methods from Files such as Files#deleteIfExists() and Files#list(Path)

    • Pros:

      • Methods can throw an IOException which can help to diagnose issues.

    • Cons:

      • However, certain usages of these methods can result in an AccessDeniedException which contributes to a less stable application.

3.2. Undo/Redo feature

The undo command allows user to undo by one command (if the command is undoable). The redo command allows user to return to the original state before latest undo.

3.2.1. Implementation

The undo/redo feature utilizes various classes to operate, such as CommandHistory class and the classes within the events package in the logic component.

CommandHistory is a static class that contains the undoEventStack and redoEventStack of the application, each containing Events.

KEY IDEA:

Event — Every UndoableCommand can be wrapped into its own unique Event.
undo/redo — Every Event has an undo and redo method.
EventFactory — An Event object is generated by the EventFactory when executing the UndoableCommand.

List of UndoableCommand:

add activity/ accommodation/ contact/ days

delete activity/ accommodation/ contact/ day

edit activity/ accommodation/ contact

schedule

unschedule

autoschedule

optimise

clear

Step 1. The user executes an UndoableCommand.

Step 2. The UndoableCommand is executed, generating an Event in the process.

Step 3. EventFactory will parse the UndoableCommand to generate an Event.
(eg. DeleteActivityCommand will result in DeleteActivityEvent generated)

EventFactory is a static class that will parse an UndoableCommand and generate the corresponding Event.

Step 4. Event is added to undoEventStack stored in CommandHistory. The redoEventStack in CommandHistory is also cleared upon generating a new Event.

Step 5. The UndoableCommand has been executed, returning a CommandResult to be shown.

Step 6. To undo the previous UndoableCommand, the user executes undo command. An UndoCommand is generated.

Step 7. UndoCommand is not an UndoableCommand. Executing the UndoCommand gets the Event from the top of undoEventStack and calls the undo method of Event.

Both UndoCommand and RedoCommand are not UndoableCommands, no Events are generated.

Step 8. The Event is popped from the undoEventStack and pushed to redoEventStack in CommandHistory. A CommandResult is returned and the Event is undone.

Step 9. To redo the command that has been undone, the user executes redo command. A RedoCommand is generated and it is not an UndoableCommand. This execution is similar to steps 6 and 7, except Event is popped from redo stack instead and pushed to undo stack.

The following two sequence diagrams shows how the user’s input is handled for 'delete activity 1'.

The first diagram below shows the execution of 'delete activity 1' command. It shows how the Event is generated and how the undoEventStack and redoEventStack is updated.

DeleteActivitySequenceDiagram
Figure 15. Executing delete activity
When DeleteActivityCommand is executed, it generates the activityToDelete by extracting the Activity to be deleted from the Model’s list of activities based on the index specified in user’s command input. It then calls the Model’s deleteActivity method.

The second diagram below shows the execution of undo command. Executing UndoCommand calls undo of the DeleteActivityEvent, which returns an AddActivityCommand with the Activity (initially deleted) to be added back at the correct index. Both Activity and Index were stored in DeleteActivityEvent.

This new AddActivityCommand is executed, and the DeleteActivityCommand is successfully undone.

UndoDeleteActivitySequenceDiagram
Figure 16. Executing undo for 'delete activity'
Each Event stores the necessary data required by the reverse Command to undo the effects of the initial UndoableCommand.
(eg. AddActivityEvent stores the Activity added, as DeleteActivityCommand requires the Activity to undo the initial AddActivityCommand’s changes)

The following activity diagram summarizes what happens when a user executes an UndoableCommand, an UndoCommand, a RedoCommand, or any other Commands.

UndoRedoActivityDiagram
If the user does not execute an UndoableCommand, UndoCommand or RedoCommand, the stack of Events in CommandHistory will not be affected.
(eg. view, list commands)

3.2.2. Design Considerations

Aspect: How undo & redo executes
  • Option 1 : Wrap every UndoableCommand in an Event class, which has undo and redo methods.

    • Pros:

      • Uses less memory by storing Event objects rather than storing every state of the Model.

      • Convenient for future extensions for new Commands added. Just need to ensure for every UndoableCommand, there must be a Command that is able to undo its changes.

      • Command classes obey Single Responsibility Principle, they do not need to know how to undo or redo itself, as it is abstracted to their corresponding Event classes.

    • Cons:

      • Every UndoableCommand requires another Command to undo its changes. Might be difficult to manage if more UndoableCommands are added.

  • Option 2 : Saves the entire Model data (comprising of accommodations, activities, contacts and days).

    • Pros:

      • Easy to implement.

    • Cons:

      • May have performance issues in terms of memory usage. Expensive to store the various objects at every state.

Aspect: Data structure to support the undo/redo commands
  • Option 1 (current choice): Use of static class CommandHistory to store a stack of Events to undo, and a stack of Events to redo.

    • Pros:

      • Easy to implement and understand. Every Event object is generated through EventFactory and stored in CommandHistory.

    • Cons:

      • Static class is used instead of Singleton implementation. No single instance of CommandHistory is created, cannot be passed as a parameter to other methods and treated as a normal object, hence might pose a difficulty during extensions.

  • Option 2: Create a HistoryManager class to store a single list of Model objects for undo/redo

    • Pros:

      • Straightforward and easy implementation, storing a deep copy of Model whenever an UndoableCommand is executed.

    • Cons:

      • Need to keep track of the Model object obtained from the list to set during Undo/Redo. Difficult to manage the pointer in the list.

3.3. Schedule optimisation

3.3.1. Implementation

Scheduled activities in a day can be modeled as a Directed Acyclic Graph (DAG) where the vertices are the activities and an edge from 1 vertex to another means that the activities are not overlapping. Just like DAGs, there are no cycles within the schedule due to the linearity of time. When the command is executed, an adjacency list is formed from the existing activities within the schedule. The paths are then traced, with the help of a utility method, from the adjacency list to find all possible combinations of activities such that there are no overlaps between activities. The list of paths are then sorted by their total cost. If there are multiple paths with the same total cost, the one with the most number of activities is selected. The existing day is then replaced with a day that contains the new schedule made from the path.

  • optimise INDEX_OF_DAY — optimises and de-conflicts the schedule. This operation supports activities with or without a cost. Activities without a cost have a default cost of $0.00.

Given below is a sample usage of the feature:

The user calls optimise command on an existing day with overlapping activities within its schedule. This results in a schedule without overlaps such that the lowest overall cost and the most number of activities if there are multiple combinations with the same total cost, such that the user’s time is maximised.

Shown below is a summary of the execution of the command.

OptimiseSequenceDiagram

3.3.2. Design considerations

Aspect: Algorithm to de-conflict

  • Alternative 1 (current): Find all combinations, if the total cost is the same, combination with more activities is selected.

    • Pros:

      • Allow users to maximise time by squeezing more activities into the schedule.

      • Allow optimisation to cover more criteria such as cost, number of activities, etc.

    • Cons:

      • Costly runtime.

  • Alternative 2: Use Single Shortest Path (SSSP) algorithms to find a combination without conflicts.

    • Pros:

      • Fast runtime.

    • Cons:

      • Use of SSSP algorithms like Djikstra or Bellman Ford restricts the criteria of optimisation due to the limits of edge weight (i.e. cost).

Aspect: De-conflict process

  • Alternative 1 (current): Model as a DAG and find combination with the lowest overall cost.

    • Pros:

      • Easy for users to use, less hassle for indecisive users.

    • Cons:

      • Less control for the user to choose activity.

  • Alternative 2: Allow users to manually de-conflict by selecting individual activities they wish to keep.

    • Pros:

      • Users have more control over activities.

    • Cons:

      • Users have to enter multiple inputs to de-conflict.

3.4. Schedule feature

Plan²travel allows user to schedule an activity from the activity list to a specified time of a day. This is accomplished by executing the ScheduleCommand with activity index, start time and day index.

Eg. schedule ACTIVITY_INDEX st/START_TIME d/DAY_INDEX

3.4.1. Current Implementation

The keywords from the command given by user is parsed using ScheduleCommandParser which converts the string variable of start time into a LocalDateTime object, while activity index and day index are converted into Index objects. These are then passed to the ScheduleCommand for execution later on.

Given below is a sequence diagram showing the creation of ScheduleCommand:

ScheduleCommandCreation
Figure 17. Sequence diagram showing how ScheduleCommand is created.

After the creation of ScheduleCommand, LogicManager will proceed to call the execute() method of ScheduleCommand.

Below are the steps taken during the execution of ScheduleCommand:

  1. Model will retrieve the list of days from the Itinerary and the list of activities from UniqueActivityList.

  2. The activityIndex and dayIndex will then be used to obtain the targeted Activity from activity list and targeted Day from list of days.

  3. Activity will be converted to ActivityWithTime using the startDateTime and duration of activity.

  4. This ActivityWithTime is then added to the list of ActivityWithTime in the target Day.

  5. The list of ActivityWithTime is sorted according ActivityWithTime startDateTime.

Given below is a sequence diagram showing the execution of ScheduleCommand:

ScheduleCommandExecution
Figure 18. Sequence diagram showing how ScheduleCommand executes.

3.4.2. Design Consideration

Aspect: Update activities for that particular day
  • Current Choice: Directly updates the activity list in the targeted Day class.

    • Pros: Seem more intuitive and simple to implement.

    • Cons: Might make it harder to debug error that surface if many other functions/classes also depends on the same Day class.

  • Alternative: Create a new Day class with the new updated activity list to replace the targeted Day class.

    • Pros: Easier for developer to test the code.

    • Cons: Might create unnecessary overheads in the code by creating new object every time we schedule an activity.

3.5. Auto Schedule feature

3.5.1. Rationale

There are times when users are planning for an overseas trip, there are so many activities in their activity list that they want to do but the problems faced are that they are unable to finish all the activities in the list or they are unable to find an optimal schedule plan.

3.5.2. Overview

The autoschedule command requires user to specify either the tag name or the activity name itself in order of the type of activity that they want. For example, t/shopping t/sightseeing t/dining would means an activity of shopping type would be scheduled first followed by sightseeing and then dining. Before using the autoschedule command, users are to fill up their activity list first and ensure that they have input the duration for each activity and are recommended to input their priority for those activities. Afterwards, autoschedule would serve to ensure that the activities scheduled do not overlap, are according to what the users prioritised first and that all activities have a chance to be scheduled.

3.6. Implementation

The keywords from the command given by the user is parsed using AutoScheduleCommandParser which converts all the tag or name prefix’s argument with their respective start time ,if given, in NameOrTagWithTime class and stores them in a list to maintain the same ordering as given by the user.

If address is specified, it is wrapped in an Address class and if the day index(es) to schedule are specified, they stored in a list with each index wrapped in an Index class. The list of NameOrTagWithTime, address and list of day indexes are then passed to the AutoScheduleCommand for execution later on.

Given below is a sequence diagram showing the creation of AutoScheduleCommand:

AutoScheduleSequenceDiagram
Figure 19. Sequence diagram showing how AutoScheduleCommand is created.

Below are the steps taken when executing of the AutoScheduleCommand:

Step 1. AutoScheduleCommand will firstly get the list of days and list of activities from the Model class

Step 2. If address is specified, the list of activities will be filtered to get all activities that has the same address.

Step 3. If no day indexes to schedule are being specified, AutoScheduleCommand will generate a schedule for all days.

Below shows the checks taken by AutoScheduleCommand:

AutoScheduleActivityDiagram1
Figure 20. Activity diagram showing how AutoScheduleCommand checks the requirement given by user:

After filtering the activity list, AutoScheduleCommand will proceed to begin preparation for the scheduling of the first activity of those specified day(s).

Step 4. It will filter the activity list that has been filtered by address to get all the activities with the same tag or activity name as the first activity to schedule.

Step 5. After which it will sort the list such that the activity that has not been scheduled will be scheduled first.It will ensure that for cases where both activities has not been scheduled before, the one with the higher priority will be scheduled first.

AutoScheduleActivityDiagram2
Figure 21. Activity diagram showing how AutoScheduleCommand handles the preparation for the scheduling of the first activity:

Step 6. Next, AutoScheduleCommand will check if the chosen activity to be scheduled does not overlap with the start time of the next activity if user specify.

Step 7. If the chosen activity overlaps, it will traverse the filtered list, picking the next activity with the next lowest count in the itinerary and check if it overlaps. The process will continue until it finds a suitable activity or it has finished traversing the whole filtered list. If it is planning for the last activity of the day, it will instead check whether the activity chosen overlap til the next day.

AutoScheduleActivityDiagram3
Figure 22. Activity diagram showing how AutoScheduleCommand finds an activity to schedule:

Step 4 to Step 7 will repeat for the next activity to schedule for that day until it finished scheduling for that day or it could not find a suitable activity to schedule. If there other days to schedule, the steps taken will also be the same as Step 4 to Step 7.

3.6.1. Design Considerations

Aspect: Counting the number of times similar activity of the same name or tag appears in the list
  • Current Choice: Count the number of times all the similar activities appear in the itinerary every time we are planning to schedule an activity.

    • Pros: It will ensure that the count number for the similar activities will always be right before they are chosen to be scheduled

    • Cons: Slow down the program as we have to traverse through all the activities for each day everytime we are planning to schedule for an activity.

  • Alternative: Have a counter inside the activity itself to keep track

    • Pros: Significantly improve the runtime speed and less complicated to implement

    • Cons: Over time, the count might be inaccurate due to multiple scheduling and unscheduling which alter the count number and we might not have keep track of it at certain point of time.

Aspect: Account for travelling time
  • Current Choice: Allows user to input the start time of activity

    • Pros: Gives user the flexibility and they are better able to gauge the travelling time of each activity

    • Cons: It restrict the number of possible activities that could be scheduled as we have to consider activity not overlapping with the start time of the next activty.

  • Alternative: Fix a break of 30min between every activity to acount for travel time

    • Pros: Activities that user prioritised are more likely to be scheduled as we do not have to consider overlap of the start time of next activity.

    • Cons: Certain activity may require more travelling time. If we fix a longer travelling time, it might not be optimising the schedule plan as certain activity might have shorter travelling time.

3.7. Auto Complete feature

3.7.1. Rationale

There are many commands to learn in our program and some of the commands can be wordy. In order to ease the learning curve and to help the user be productive as quickly as possible, autocomplete was implemented.

3.7.2. Implementation

KEY IDEA:

Every command in the planner can be broadly broken down into a few categories, namely:

  1. Command Word

  2. Preamble

  3. Required Prefix

    1. That are used once

    2. That are used multiple times

  4. Optional Prefix

    1. That are used once

    2. That are used multiple times

AutoCompleteSuggester makes use of this and checks the input for these categories one by one.

  • If the input lacks the command word, then the best matching command word will be suggested.

  • If the command word is provided, but the preamble is not (and it is required by the command), then the preamble will be suggested.

  • If the input contains the command word and contains the preamble(when necessary), then the required prefixes and optional prefixes will be suggested. Since there are some prefix that should only be used, the input will be checked to see if these prefixes are present and remove them from the suggestions.

The AutoCompleteParser supports the AutoCompleteSuggester by parsing the user input into the command word, the preamble and a list of prefixes used in the program.

Given below is a sequence diagram showing the generation of suggestions:

AutoCompleteSuggesterSequenceDiagram
Figure 23. Sequence diagram showing the generation of suggestions.
AutoCompleteSuggesterGetPossibilitiesSequenceDiagram
Figure 24. Sub diagram for getPossibilities

Below is how the autocomplete feature is triggered:

Step 1. Modification in the text of AutoCompleteTextField is detected.

Step 2. If the input is empty, hide the pop-up box which contains the suggestions. If not empty, get entries (suggestions) for the pop-up box.

Step 3. If there are entries, populate the pop-up box with it. Else, hide the pop-up box.

Step 4. If pop-up box in previous step was populated, then show the pop-up box to the user.

AutoCompleteActivityDiagram1
Figure 25. Activity diagram showing how the pop-up box containing the suggestions appears:

Below is how entries for the pop-up box is obtained:

Step 1. Check if input contains '<' or '>', as that would indicate that the user has accepted the suggestion of preamble, which has description enclosed with < and > (for e.g. <INDEX>) but has not replaced it with the actual preamble. If it has '<' or '>', then don’t give suggestions to user.

Step 2. If the input does not contain '<' or '>', parse the command word.

Step 3. Next check if command word can be found. If it is not found, suggest command words that partially matches what the user has already inputted. If command word was found, do a check if there is a space at the end of the input.

Step 3. Next check if command word can be found. If it is not found, suggest command words that partially matches what the user has already inputted. If command word was found, do a check if there is a space at the end of the input.

Step 4. If there is no space, don’t give suggestions to the user as it is assumed that the user is still typing. If there is a space, then parse preamble, parse prefix and make suggestions based on the command word, preamble and prefix present in the input.

AutoCompleteActivityDiagram2
Figure 26. Activity diagram showing how entries for the pop-up box is generated:

3.7.3. Design Considerations

Aspect: Underlying data structure to store the command words
  • Current Choice: Use an ArrayList

    • Pros: Simple to implement.

    • Cons: Might be slow in providing suggestion for the command word, as in the worse case, it needs to iterate through every command word entry and check with every entry.

  • Alternative: Use a Trie

    • Pros: Faster in providing suggestion for command word as it only has to iterate through the length of the input.

    • Cons: More complicated to implement. The Trie also needs to be built during startup.

  • Reason for choice: Given that the program does not have many commands and unlikely to have a significant number more commands in the future, search times are not an issue.

Aspect: Checking if the user has completed typing the command word/preamble/prefix content
  • Current Choice: Assumes the user has finished the command word/preamble/prefix content when there is a whitespace at the end of input

    • Pros: Simple to implement. Works in most cases.

    • Cons: Might be wrong when suggesting new prefix as there are some commands like autoschedule that have prefixes that can have 2 arguments (autoschedule t/argument1 argument2 d/argument1 argument2…​)

  • Alternative: Waits for a specific duration of time before giving user suggestions

    • Pros: More likely to provide suggestions when the user needs it.

    • Cons: There might be a noticeable delay in the suggestions appearing if the specific duration is too long. More complicated to implement.

3.8. Timetable

3.8.1. Current Implementation

Internally, Timetable is a List of ActivityWithTime. This gives the Timetable flexibility to accept Activities that start and end at any time instead of fixed intervals (e.g. 30 minute intervals) while allow for conflicting ActivityWithTime.

3.8.2. Design considerations

  • Alternative 1: an Array of time slots that stores Activity

    • Pros: Simple and intuitive to implement. UI for itinerary is easier to implement too. Very fast access to each Activity in the Timetable.

    • Cons: Constrained to fixed intervals. Hence, Activity start times and end times have to be in multiples of the fixed interval.

  • Alternative 2: a TreeSet of ActivityWithTime

    • Pros: Allows flexible start times and end times. Fast access to Activity in Timetable. Does not allow ActivityWithTime objects to have the same start times.

    • Con: UI for itinerary might be difficult to implement as each the size of each block of ActivityWithTime in the UI is not the same. Does not allow for conflicting startDateTime between ActivityWithTime.

  • Alternative 3(current choice): a List of ActivityWithTime

    • Pros: Allows flexible start times and end times. ActivityWithTime can have the same startDateTime, thus allowing conflicting ActivityWithTime.

    • Con: UI for itinerary might be difficult to implement as each the size of each block of ActivityWithTime in the UI is not the same. Slower access time if the size of the List is large.

3.9. Logging

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

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

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

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

Logging Levels

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

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

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

3.10. Configuration

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

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • a student who is inexperienced in planning for overseas trips

  • has a need to manage and schedule planner items

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition: Many students wish to go for overseas trips during their holidays. They may be inexperienced in trip planning. These students would benefit from having a template as a way to organise the information they have for their trip. Plan²travel can organise information faster than a typical mouse/GUI driven app.

Appendix B: User Stories

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

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

* * *

traveller

refer to a list of attractions

I can decide on what activities to do for the day

* * *

traveller

add activities that I want to do

I can plan my trip

* * *

traveller

save my contact list

I can review/access them again

* * *

traveller

access a list of accommodations

I can better plan for where to stay at

* * *

organised traveller

plan my daily planner

I can make better use of my travel time

* * *

lightweight traveller

save the planner to my phone

I can pack light

* * *

infrequent traveller

add contacts

I can get in touch with the hotel concierge

* * *

new user

view a help guide

I can familiarise myself with the application

* *

traveller

categorise activities by interest

I can prioritise certain activities

* *

solo traveller

keep a list of emergency contacts

I know who to contact in times of emergency

* *

eager traveller

follow an accommodation checklist

I will not miss out on anything

* *

indecisive traveller

plan for multiple trips

I can decide on a later date

* *

messy planner

quickly organise my travel research

I can streamline my planning processes

* *

fast typist

be auto-corrected for my typos

I won’t break my train of thought while planning

* *

advanced user

use command shortcuts

I can improve my planning efficiency

* *

advanced user

set where to save my itineraries

I can organise my itineraries

* *

careless user

undo my mistakes

I don’t have to retype if I make one

*

traveller

rate activities that I have done

I can make a better recommendation to my friends

*

traveller on a tight budget

estimate my budget for a trip

I can minimise my spendings

*

traveller

organise and record my travel experiences

I can share them online

*

inexperienced planner

receive planning recommendations

I can improve my planner

Appendix C: Use Cases

(For all use cases below, the System is the Plan²travel application and the Actor is the user, unless specified otherwise)

Use case: Schedule activity

MSS

  1. User requests to schedule activity

  2. System shows a list of days and activities

  3. User requests to add a specific accommodation to a specific day

  4. System adds accommodation under selected day

    Use case ends.

Extensions

  • 2a. The list of days is empty.

    • Use case ends.

  • 2b. The list of activities is empty.

    • Use case ends.

  • 3a. The day number is invalid.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

  • 3b. The accommodation index is invalid.

    • 3b1. System shows an error message.

      Use case resumes at step 2.

Use case: Add Contact

MSS

  1. User requests to add a new Contact

  2. System adds the new Contact into the database

    Use case ends.

Extensions

  • 1a. The new Contact’s syntax is not entered correctly.

    • 1a1. System shows a feedback to the user that the Contact was not entered correctly.

    • Use case ends.

Use case: Undo command

MSS

  1. User requests to undo last possible command

  2. System reverts to state before the last possible command

    Use case ends.

Extensions

  • 1a. There is no last possible command.

    • Use case ends.

{More to be added}

Appendix D: Non Functional Requirements

Availability

  1. Application should work on any mainstream OS as long as it has Java 11 or above installed.

Performance

  1. Application should respond within 2 seconds of client’s query.

Usability

  1. Application should be easy to use for new user when following the User Guide.

  2. Application’s interface should be intuitive and easy to understand for the user.

  3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.

Reliability

  1. Application should be able to execute all user’s commands without failing.

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Appendix F: Instructions for Manual Testing

Given below are instructions to test the app manually.

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

F.1. Launch and Shutdown

  1. Initial launch

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

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

F.2. Adding

F.2.1. Adding activities

  • Add a new activity to the planner

    1. Prerequisites: Arguments are valid and compulsory parameters are provided.

    2. Test case: add activity n/Swim at the beach a/Glass Beach du/180 p/12345678 pr/1 t/Fun
      Expected: Adds an activity named "Swim at the beach", with address "Glass Beach", a duration of 180 minutes, a contact with the phone number 12345678, a priority level of 1 and with the tag "Fun".

    3. Test case: add activity n/Swim at the beach
      Expected: No activity is added. Error details shown in the feedback display.

    4. Other incorrect add commands to try: add activity a/Glass Beach, add activity n/Swimming du/120
      Expected: Similar to previous

F.2.2. Adding accommodations

  • Add a new activity to the planner

    1. Prerequisites: Arguments are valid and compulsory parameters are provided.

    2. Test case: add accommodation n/Hotel 87 a/Hilton Crescent p/12345678 t/Cozy
      Expected: Adds an accommodation named "Hotel 87", with address "Hilton Crescent", a contact with phone number 12345678, and with the tag "Cozy".

    3. Test case: add accommodation n/Hotel 123
      Expected: No accommodation is added. Error details shown in the feedback display.

    4. Other incorrect add commands to try: add accommodation a/Kappa street, add accommodation p/87654321 t/lmao
      Expected: Similar to previous

F.2.3. Adding contacts

  • Add a new contact to the planner

    1. Prerequisites: Arguments are valid and compulsory parameters are provided.

    2. Test case: add contact n/Allan p/12345678 e/example@example.com t/Budz
      Expected: Adds a contact named "Allan", with phone number 12345678, an email of "example@example.com" and with the tag "Budz".

    3. Test case: add contact n/Big Brother
      Expected: No contact is added. Error details shown in the feedback display.

    4. Other incorrect add commands to try: add contact a/Kappa street, add contact p/87654321 t/lmao
      Expected: Similar to previous

F.2.4. Adding days

  • Add days to the itinerary

    1. Prerequisites: Arguments are valid, and NUMBER_OF_DAYS being added and number of days currently in itinerary do not exceed 15.

    2. Test case: add days 2
      Expected: Adds two days to the itinerary. Else, invalid message will be shown.

    3. Test case: add days 16
      Expected: No days is added. Error details shown in the feedback display.

    4. Other incorrect add commands to try: add days abc, add days -1
      Expected: Similar to previous === Editing an activity

      1. Editing an activity’s name

    5. Test case: Edit activity 1 n/Visit Mount Fuji Expected: The first activity in the activity list has its name being edited to Visit Mount Fuji.

      1. Editing an activity’s address

    6. Test case: Edit activity 1 a/Tokyo Expected: The first activity in the activity list has its address being edited to Tokyo.

F.3. Editing an accommodation

  1. Editing an accommodation’s name

    1. Test case: Edit accommodation 1 n/Shinjuku hotel Expected: The first activity in the activity list has its name being edited to Shinjuku hotel.

  2. Editing an accommodation’s address

    1. Test case: Edit accommodation 1 a/Tokyo Expected: The first accommodation in the accommodation list has its address being edited to Tokyo.

F.4. Editing a contact

  1. Editing a contact’s name

    1. Test case: Edit contact 1 n/Uncle Bob Expected: The first contact in the contact list has its name being edited to Uncle Bob.

  2. Editing a contact’s phone number

    1. Test case: Edit contact 1 a/90001112 Expected: The first contact in the contact list has its phone number being edited to 90001112.

F.5. Deleting a contact

  1. Removes a contact from contact list

    1. Test case: delete contact 2 Expected: Deletes the 2nd contact in the contact list.

F.6. Deleting an activity

  1. Removes an activity from contact list

    1. Test case: delete activity 2 Expected: Deletes the 2nd activity in the activity list.

F.7. Deleting an accommodation

  1. Removes an accommodation from accommodation list

    1. Test case: delete accommodation 2 Expected: Deletes the 2nd accommodation in the accommodation list.

F.8. Autoschedule

  1. Generate a schedule for specified day(s) based on the tags or activity name given.

    1. Prerequisites: Ensure the tag or activity name is present in activity list.

    2. Test case: autoschedule t/sightseeing 1030 t/dining 1200 d/1 Expected: An activity of sightseeing tagged has been scheduled at 1030 followed by another activity of dining tagged scheduled at 1200 on day 1.

F.9. Scheduling activities

F.9.1. Schedule

  • Schedule an activity to a day at a certain time

    1. Prerequisites: Arguments are valid, and end date time of the activity must not be after the end of the trip. Also, the provided index for both activity and day must be less than or equal to the size of their respective list(activity list, itinerary).

    2. Test case: schedule 1 d/1 st/1000
      Expected: Schedules activity 1 into day 1 at time 10am.

    3. Test case: schedule 1 d/16 st/1000
      Expected: Nothing is scheduled. Invalid message shown.

    4. Other incorrect add commands to try: schedule d/1 st/1111, schedule 1 d/1
      Expected: Similar to previous === Undo a delete command

      1. Retrieve the information that has been deleted.

    5. Prerequisites: Delete activity 1 has been executed.

    6. Test case: undo

    7. Expected: The activity initially in the first index of the activity list has been added back to the activity list.

F.10. Unschedule activity from day

  • Unschedules an activity from a day

    1. Prerequisites: Arguments are valid. Also, the index for the preamble is the index of the activity within the day(as shown from list day). Day DAY_INDEX must exist in the itinerary.

    2. Test case: unschedule 1 d/1
      Expected: Unschedules the first activity in day 1.

    3. Test case: unschedule d/16 st/1000
      Expected: Nothing is unscheduled. Invalid message shown.

    4. Other incorrect add commands to try: unschedule 1, unschedule 1 d/16
      Expected: Similar to previous === Undo an add command

      1. Delete the information that has been added.

    5. Prerequisites: add activity n/Visit Mount Fuji a/Tokyo du/30 has been executed.

    6. Test case: undo

    7. Expected: The activity Visit Mount Fuji is deleted from the activity list.

F.11. Undo an edit command

  1. Return back to the original state before it has been edited.

    1. Prerequisites: edit contact n/Bob has been executed.

    2. Test case: undo

    3. Expected: The contact name of Bob is deleted and is replaced by the original name before it has been edited.

F.12. Optimise a day

  1. Remove all overlapping for the day and generate a schedule with the lowest budget for the day being optimised.

    1. Prerequisites: There are activities scheduled for the specified day to optimise.

    2. Test case: optimise 1

    3. Expected: Activities that are non-overlapping and they have the lowest cost in total are chosen for that day.

F.13. List activity

  1. All activities in activity list are listed

    1. Test case: list activity

    2. Expected: All activities are listed in the information panel.

F.14. Set

  • Sets the name or start date of the itinerary

    1. Prerequisites: Arguments are valid. A minimum of either name or start date must be provided.

    2. Test case: set n/Germany sd/25-12-2019
      Expected: Sets the itinerary name to Germany and start date to 25th Dec 2019.

    3. Test case: set
      Expected: Nothing is set. Invalid message shown.

    4. Other incorrect add commands to try: set sd/12/12/2019
      Expected: Similar to previous

F.15. New

  • Creates and loads a new empty trip with desired name

    1. Prerequisites: Arguments are valid and no existing saved trips have the same name. A name must be provided.

    2. Test case: new n/Japan Trip
      Expected: Creates a new empty trip named "Japan Trip". The name is reflected as the itinerary name.

    3. Test case: new
      Expected: Planner name not specified

    4. Test case: new n/Iceland Trip, new n/Iceland Trip
      Expected: This planner already exists

F.16. Copyto

  • Creates and loads a copy of current trip using desired name

    1. Prerequisites: Arguments are valid and no existing saved trips have the same name. A name must be provided.

    2. Prerequisites: Populate a new trip using the following commands:

      1. new n/China v1

      2. add activity n/Visit QinShiHuang’s Tomb a/Xi An du/240 t/history

      3. add accommodation n/China World Hotel a/Beijing t/5star

    3. Test case: copyto n/China v2
      Expected: Creates a copy of the current trip named "China v2". The name is reflected as the itinerary name and is the only visible difference when compared to the original trip.

    4. Test case: copyto
      Expected: Planner name not specified

    5. Test case: copyto n/China v1
      Expected: This planner already exists

F.17. Load

  • Loads a saved trip with desired name

    1. Prerequisites: Arguments are valid and no existing saved trips have the same name. A name must be provided.

    2. Prerequisites: Populate 2 new trips using the following commands:

      1. new n/China

      2. add activity n/Visit QinShiHuang’s Tomb a/Xi An du/240 t/history

      3. add accommodation n/China World Hotel a/Beijing t/5star

      4. new n/Japan

      5. add accommodation n/Crowne Hotel a/Tokyo p/8137973142 t/5stars

      6. add activity n/Visit Aquarium a/Tokyo p/812487941 du/120 c/20.00 pr/3 t/marine

    3. Test case: load n/China
      Expected: Loads the existing trip that has the name "China". The name is reflected as the itinerary name.

    4. Test case: load
      Expected: Planner name not specified

    5. Test case: load n/China
      Expected: This planner has already been loaded

F.18. View

F.18.1. View activity/accommodation/contact

  • Views information about an activity/accommodation/contact

    1. Prerequisites: Argument is valid. The provided index for activity must be less than or equal to the size of the activity list.

    2. Test case: view activity 1/view accommodation 1/view contact 1
      Expected: Views the information about activity/accommodation/contact 1.

    3. Test case: view activity abc/view accommodation abc/view contact abc
      Expected: No information about activity/accommodation/contact appear. Invalid message shown.

F.18.2. View itinerary/info/help

  • Switch tab to itinerary/info/help

    1. Test case: view itinerary/view info/view help
      Expected: Switches tab to itinerary/info/help.

F.18.3. Redo

  • Redo the last undo command.

    1. Prerequisites: Only to be used if undo had been used.

    2. Test case: redo
      Expected: Redo the last undo command.