Overview

My team and I were tasked with enhancing, or morphing an existing address book application built on JavaFX for our software engineering project.

We chose the latter, which’s end product was TravelPal, a desktop travelling companion application catered for leisure travellers. TravelPal allows travellers to manage their travelling itinerary, bookings, expenses and inventory conveniently in one place, and record their travels in a diary.

As per the constraint given to us in developing this project, the user interacts with TravelPal mainly using a command line interface (CLI), although it has user interface alternatives for most of its operations.

My main role was to develop the diary feature, which allows the user to store and edit memorable details of their trip with both multimedia and text.

Summary of contributions

Main contribution 1: Implemented the diary feature.

welcome to diary image
  • What: Overall, this feature allows the user to key in memorable details of his / her travels, and store multimedia such as photos of the trip, displayed in a user friendly and eye-catching format.

  • Justification: Leisure travellers often want to reminisce on previous trips they have made long after the trip, or share its details with friends and loved ones.

  • Highlights: Due to the large amounts of displayable multimedia, the user interface of this feature was most challenging to implement, requiring much analysis and consideration in striking a balance between code performance and organization. To ensure support for various forms of multimedia in the future, the user interface implementation also had to be highly extensible.


Main Contribution 2: Base address book code refactor

forms
  • What: I added and updated several ui components, which of particular note was ui FormItems, a convenient and reusable code structure to build user input forms anywhere in TravelPal. I also refactored all of the logic code component of the base address book code for team use in TravelPal.

  • Justification: Given the limited time frame of our project, it was crucial that we utilised much of the existing code to speed our development process, and develop code components that were easily reusable.

    In addition, although the code base given to us was extensive, much of the common functionality we had in mind for TravelPal, such as the ability to switch between pages of the application, were not immediately implementable from the given address book code base.

  • Highlights: In achieving the desired functionality, it was challenging to avoid making intrusive changes to the code base whenever possible, as it would introduce additional burden for the team in understanding the code.


Other Contributions

  • Code contributed: [RepoSense code] [Github pull requests]

  • Idea generation:

    • Contributed main idea of TravelPal and its various sub-features (itinerary, diary, expenses, etc.) during project inception, which the team agreed upon. (see travelpal idea generation google docs)

  • Feature additions and enhancements

    • Implemented the trip manager screens, serving as the entry point to the TravelPal application #34

    • Enhanced navigation bar icon looks #68

  • Project management:

    • Managed releases v1.1 - v1.4 (4 releases) on GitHub: releases

    • Maintained issue tracker for milestones 1.1 through 1.4 issues

  • Tools:

    • Set up several continuous integration services (AppVeyor, Coveralls)

    • Set up team github organization and repo

Contributions to the User Guide

In developing TravelPal, a completely new user guide was needed to provide usage instructions for the various new features.

Shown below is one of the various sections I contributed to the User Guide, on adding a photo to display in the diary feature.

Adding a photo

If you have just created a fresh diary entry, and you’re wondering where to go next, then you may want to start by adding your photos to display in the gallery ([diary_gallery_display]).

There are 3 ways for you to add a photo, the last option being the least flexible but also the fastest!

In all options, the image file chosen should be of the file types .jpg, .jpeg, or .png.
Option 1: Using the addphoto command with the fp/ prefix
  • Usage: Typing in the command addphoto fp/<file path> [d/<description>] [dts/<date taken>], with the arguments described below, will add the image located at the file path on your computer to the gallery.

  • Arguments:

    • <file path> - Relative file path from the location of the TravelPal’s jar file, or an absolute file path. (see [glossary] for details of relative and absolute file paths)

    • <description> (optional) - The description of the photo to be shown in the gallery, of maximum length 20. If unspecified, the file name is used instead, shortened to the maximum length.

    • <date taken> (optional) - The date taken of the photo, of the format d/M/yyyy HHmm. If unspecified, the last modified date of the file is used instead.


Example Usage

Scenario:

  • You are currently viewing an empty diary entry for day 1 and you want to add a new photo.

  • Also, you want to give the photo a custom description, but want to use the last modified date of the image file in your computer as the date taken for the photo.

  • Shown below is an example of the photo on your computer you want to add, snowymountains.jpg, that is located in the same place as the TravelPal application.

diary addphoto filepath directory
Figure 1. Example file directory structure of the TravelPal application and snowymountains.jpg
  1. You should type in the addphoto fp/snowymountains.jpg d/picturesque mountains command in the command line input, and press the 'enter' key.

    1. Here, the relative <file path> is simply the name of the file, snowymountains.jpg, since the image file is located in the same directory as the TravelPal application.

      diary addphoto command filepath
      Figure 2. Example usage of the addphoto command with the fp/ option
  2. That’s it! The photo, with the specified description and last modified date will be added. You should see a brief confirmation message in the command result box.

    1. Additionally, there will be a auto-generated photo numbering, for use as described in [diary_text_displaying_images].

diary addphoto command filepath result
Figure 3. Example result of after executing the addphoto command with the fp/ option

Option 2: Using the addphoto command with the fc/ prefix
  • Usage: Typing in the command addphoto fc/ [d/<description>] [dts/<date taken>], with the optional arguments described below, will open your system’s dialog to choose an image file.

  • Arguments (optional):

    • <description> - The description of the photo to be shown in the gallery, of maximum length 20. If unspecified, the file name is used instead, shortened to the maximum length.

    • <date taken> - The date taken of the photo, of the format d/M/yyyy HHmm. If unspecified, the last modified date of the file is used instead.

Using both the fc/ and fp/ prefix will cause TravelPal to ignore the fp/ prefix!
  • Usage: Clicking the Add button located under the gallery display area ( [diary_gallery_button_bar]) will open your system’s dialog to choose an image file.

  • If this option is used, then the <description> & <date taken> are not specifiable and will be auto generated as described above.


Example Usage for addphoto command with the fc/ option or add button
See the user guide for this usage scenario, not included in this project portfolio page.

Contributions to the Developer Guide

In the course of this project, my team and I realised we developed a substantial amount of code on top of the code base given to us. Hence, we updated the TravelPal developer guide to reflect the changes we needed.

Below is one of the various sections I contributed, documenting the aspect of the diary that stores and displays photos.

[Diary] Photo Manager

The photo manager pertains to components for storing, and displaying user specified photos on the disk.


Aspect: Models

DiaryPhotoModelClassDiagram
Figure 4. Class diagram of a PhotoList as contained by a diary entry, and its contained models
Photo

The model for a photo stored in memory is stored in the DiaryPhoto class.

It contains three key fields, that is, the imagePath, description, and dateTaken fields which are used to display key information of the image to the user. The imagePath and dateTaken were implemented respectively with the robust java apis of Path and LocalDateTime, while description is simply a String.

In addition, a JavaFX Image is also stored inside the DiaryPhoto (not shown in Class diagram of a PhotoList as contained by a diary entry, and its contained models for brevity), which holds the Image to use for displaying in an ImageView inside the user interface. The Image is cached this way, as on-demand Image construction in the user interface involves costly I/O operations.

Restrictions on fields during DiaryPhoto instance construction:

  • Several restrictions on the description are enforced by class level Pattern matchers, such as the length of the description.

  • While the image file path is parsed and checked using the java Files api, it is non-strict in that a path to an invalid image will result in the Image field referring to the default class level variable that specifies a placeholder image.

    • However, the original user entered file path is still stored inside the Model, to guard against accidental file deletion.

PhotoList

On the other hand, the DiaryPhoto models are contained within a PhotoList. It stores the photos in a JavaFX ObservableList, so that changes are registered with the user interface. (see Aspect: User interface of photo manager)

It also supports several convenience wrapper methods around the underlying ObservableList, tailored for use for the logic components.


Aspect: User interface of photo manager

The main UiPart component that displays photos is the DiaryGallery. It abides by the Page implementation (see [page_api]), and is thus contained within, in one of DiaryPage’s placeholders.

DiaryPhotoUiObjectDiagram
Figure 5. Object diagram of the diary gallery component, as contained by DiaryPage (not shown)

The main JavaFX component responsible for displaying the photos is a ListView<DiaryPhoto> component. The ListView obtains its data from the PhotoList of the DiaryGallery, which is automatically observed by the ListView.

Hence, changes in the PhotoList, such as the addition of a DiaryPhoto are immediately communicated to the user interface.

The ListView uses a simple custom cell factory, which sets the ListCells of the ListView to use DiaryGalleryCards as its graphic. DiaryGalleryCards are in turn generated in the cell factory using the ListCell’s index and a DiaryPhoto instance.

DiaryGalleryCards display the information as supplied by the DiaryPhoto model using a series of Labels and one ImageView. Additionally, the index of the card as ordered in the DiaryGallery is also displayed, but not stored in the model.


Aspect: Logic of photo manager operations

The logic for photo manager plays to the same PageParser structure of parsing commands, that is, DiaryParser returns either AddPhotoParser, DeletePhotoParser when the appropriate command word is parsed, which in turn returns instances of AddPhotoCommand and DeletePhotoCommand respectively.

Logic aspect 1: Adding photos (through command line file path or os file chooser)

Following DiaryParser returning an instance of AddPhotoParser that calls parse() on the user specified arguments, a number of operations happen, as per the UML sequence diagram below ([addphotoparser_parse_sequence_diagram]). The specifics of getFilePath, parseDescription, parseDateTime are detailed further down below.

addphotoparser_parse_sequence_diagram
Figure 6. Sequence diagram of the parse method in AddPhotoParser
Parsing the image file path
  • Using ArgumentMultimap, the file chooser prefix, fc/, is checked for. If present, the OS file choosing gui is opened using ImageChooser (a simple extension of JavaFX’s FileChooser enforcing image file extensions), and the data file path prefix is ignored.

  • The getFilePath subroutine is then called, detailed in Activity diagram of getFilePath subroutine, which checks for the existence and validity of the image as supplied by the ImageChooser or the file path in the fp/ argument.

  • If the fc/ was unspecified and the parsing process fails any of the checks, getFilePath throws a ParseException.

AddPhotoParserGetFilePathActivityDiagram
Figure 7. Activity diagram of getFilePath subroutine
Parsing the description of the photo
  • If the description prefix is present, AddPhotoParser tries to construct the DiaryPhoto instance with the specified input. If validation of the description, as described in Aspect: Models fails, then a ParseException is thrown during the instance construction.

  • Otherwise, the file name of the validated file from Parsing the image file path (truncated to match DiaryPhoto’s description constraints) is used.

AddPhotoParserParseDescriptionActivityDiagram
Figure 8. Activity diagram of parseDescription subroutine
Parsing the date of the photo
  • If the date time prefix is present, ParserDateUtil is used to parse the input as per the app level date formats. A ParseException is thrown in the case of date parsing failure, by ParserDateUtil.

  • Otherwise, the last modified date of the validated file from Parsing the image file path is used.

The DiaryPhoto instance is then constructed, and passed to AddPhotoCommand which simply adds the DiaryPhoto to the current PhotoList of the DiaryEntry.

Logic aspect 2: Deleting photos

Following DiaryParser parsing the 'delphoto' command from the user, an instance of DeletePhotoParser is created, which parses the received arguments.

  1. The DeletePhotoParser simply parses the arguments for a valid integer, failing which a ParseException is thrown.

  2. An instance of DeletePhotoCommand is then returned, which attempts a delete operation on the current PhotoList of the DiaryEntry with the specified index. A CommandException is thrown to alert the user if the index was out of bounds.


Design considerations

Feature Alternative 1 Alternative 2

Validation of image file path

The first option is to implement the file path validation directly inside the DiaryPhoto model.

This would have enforced a stricter level of validation on the image file path throughout the code, such as if an instance of DiaryPhoto needed to be instantiated somewhere else other than the AddPhotoParser class for future use.

However, since the storage model for DiaryPhoto (JsonAdaptedDiaryPhoto), initializes the model through reading the saved file path, this would have led to needing to a separate constructor for DiaryPhoto if the file path read on app startup was no longer valid, in order to create a placeholder image.

This secondary constructor would thus defeat the defensive benefit of implementing validation directly in the model.

The second, chosen option, was to implement the file path validation inside the parser itself.

Although this option limited the validation to only the 'addphoto' command, it allowed for leeway in image path validation in other areas such as JsonAdaptedDiaryPhoto, where it is possible for deletion of an image file by the user, outside of the application, to invalidate the stored file path.

Moreover, Since the function for parsing the image file can and was abstracted into a single utility function, any other areas in future development needing this functionality can simply reuse this code.

Overall, this leads to a more robust behaviour of the application, while providing the same level of extensibility as the first option.

Conclusion

The constraints imposed on our development process necessitated careful deliberation and consideration of both our product, TravelPal, and the changes needed to our code. From this process, I gained many invaluable insights for future software projects, particularly in the area of requirements analysis.

Nonetheless, using my prior experience, I was able to contribute and implement numerous suggestions which resulted in an extensible code base, easing the team development process.

Overall, developing TravelPal proved to be both a challenging and fruitful experience for me.