1. Project: 'Savee' - A Desktop Financial Planner

2. Overview

2.1. Project & Product Information

'Savee' is a desktop financial planner application my team of 4 created for our Software Engineering Principles module. Our main project was to morph an existing code into any other software we opted to. We were evaluated based on our ability to work with existing base code and the quality of our new modifications to the existing code.

Savee has a command-line interface (CLI) and graphical user interface created using JavaFX. It is for users who enjoy typing to manage their finances responsibly using a desktop interface. The application revolves around usage of the CLI to manage one’s finances. Users can store a Record consisting of name, moneyflow, date and tags of any form of financial activity in the application.

3. Summary of Contributions

3.1. Major Enhancement: ability to autocomplete text input

  • Function: display a popup-box of suggested words to autocomplete with when user inputs parts of a word.

  • Significance: Improves the product significantly for users who may not be familiar with the software commands and can save time by keying in parts of a command word and simply complete the command using the list of suggested words.

  • Key Highlights: To create an effective autocomplete by words instead of entire text, I needed to accurately read the the entire user input and provide a variable range of suggestions. While it may seem a simple feature, I wrote an extensive amount of code for this feature to ensure the auto complete performed its role successfully for most of the functions in our software.

  • Credits: The Java TextFields (AutoComplete) Library and its inner classes were recreated and tweaked to achieve the necessary aims of our product autocomplete functionality.

3.2. Minor Enhancement #1: ability to find data by tags

  • Function: allows users to find and display all data with a specific attribute tag.

  • Significance: As mentioned in [Product Information], each data can be categorised with tags. This feature improves the product by providing another means of filtering data according to their needs.

3.3. Minor Enhancement #2: ability to sort data

  • Function: allows users to sort their data by a specific category and in a specific order

  • Significance: This feature improves the product by providing users with different means of manipulating and reorganising their data. This was a simple but much needed functionality. =

3.4. Other Contributions

  • [My Project Code]

  • Project management:

    • Pull requests made had to be approved by one other team member and I helped to evaluate pull requests to ensure only necessary changes to the code was merged.

    • Pull Requests reviewed (with non-trivial review comments) #17

    • Added and improved utility methods for comparison and sorting that were easily reusable. (Pull requests #64)

    • Made significant changes to reorganise User Guide user readability. (Pull Request #114)

4. Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

4.1. AutoComplete

This section describes the auto completing feature implemented on the input command box which makes the typing interface of Savee more friendly and efficient.

A list of possible words will be displayed in a popup-box under the command box according to the user input. Word suggestions are displayed when all letters of the current input word match the beginning of the word in the suggestion word bank. e.g to suggest the word expenditure user can key in either e, ex, exp and so on, which can all suggest the expected word. However, the expected word must exist in the appropriate word bank which will be described in [Features].

User may use the keys to navigate the list and select a word they wish to complete their input with using Enter. If user does not wish to select a word for completion, user may press ESC or Space or mouseclick anywhere else in the command box to move onto another word. Auto completion is performed word by word and after completing a word, the typing caret will appear at the end of the newly completed word. Previously existing text before and after the completed word will not be lost and will be shifted accordingly.

When the suggestion window is not open, user may use and to navigate the text and may go back to change previously entered texts. These texts will also allow autocompletion if possible, depending on the command in use and parameters already entered.

  • While a list of suggestions is active, users may not perform some actions such as or Ctrl+A.

  • Word suggestions are not case sensitive. e.g. HEL will have a possible suggestion help.

  • Whitespaces will not affect the accuracy of the autocomplete.

4.1.1. Autocomplete for add Command

  • Names

    • Inputs starting with n/ and words that come after it but before the next prefix m/, d/ or t/ use can be completed with names.

    • Suggested words will be suggested based on words used in existing records' names e.g if an earlier inserted record is named Dinner with Family, then Dinner with Family can all be possible suggestions.

  • Dates

    • Inputs starting with d/ can be completed with dates.

    • Dates must be entered as with the normal constraints and also have 2-digits for both day and months. e.g to have a suggestion of 01-11-2018 to appear, you have to key in d/ 0 for that date to appear. d/ 1/ will not work.

    • Dates that are suggested will also only come from earlier saved records.

    • Can also be completed to today or ytd.

  • Moneyflow

    • Does not offer auto completion.

  • Tags

    • Inputs starting with t/ can be completed with tags.

    • Tags will also only from from earlier saved records' tags and a pre-existing set of tags such as e.g. food, travel, bills, shopping.

  • There is no autocompletion restriction on number of names, dates, moneyflow or tag inputs but command will still require the appropriate number of parameters.

4.1.2. Autocomplete for sort Command

  • Input word suggestions are suggested based on what can still be filled in.

    • If a category has been specified, only an order can be suggested and vice versa.

    • If neither has been specified, then both order and category are possible suggestions.

  • There will be no suggestions on parameters that come after the third.

4.1.3. Autocomplete for summary Command

  • Mode Keyword

    • First parameter after the summary keyword can be completed to date, month or category.

  • Dates

    • Input text can be completed to dates that already exist in records in Savee.

    • Inputs starting with d/ can be completed with dates as well as the argument that come immediately after the entire d/DATE input as long as there are only whitespaces between them.

    • Text can also be completed to today or ytd.

  • Months

    • Input text can be completed to months with year in the form e.g nov-2018.

    • Suggestions are currently limited to inputs from jan-2018 to dec-2018.

  • There will be no suggestions on parameters that come after the fourth.

4.1.4. Autocomplete for exportexcel Command

  • Dates

    • Input text can be completed to dates that already exist in records in Savee.

    • Inputs starting with d/ can be completed with dates as well as the argument that come immediately after the entire d/DATE input as long as there are only whitespaces between them.

    • Text can also be completed to today or ytd.

  • Directory

    • Does not offer auto-competion.

  • There will be no suggestions on parameters that come after the fourth.

4.2. Locating records by tag: findtag

Finds records with tags that match any of the given keywords.
Format: findtag KEYWORD [MORE_KEYWORDS]

  • The search is case insensitive. e.g hans will match Hans

  • The order of the keywords does not matter. e.g. Hans Bo will match Bo Hans

  • Only the tags are searched.

  • Only full words will be matched e.g. Han will not match Hans

  • Records with tags matching at least one keyword will be returned (i.e. OR search). e.g. friends food will return all records tagged with either friends or food.

Examples:

  • findtag friend
    Returns any record tagged with friend

  • findtag friend food shopping
    Returns all records having any of the tags friend, food, or shopping

4.3. Sorting displayed records : sort

Sorts the list of records in the record book by a category. There are 3 categories to sort by name, date, moneyflow/money and records can be sorted in either ascending order asc or descending order desc.
Format: sort [CATEGORY] [ORDER]

  • Only the abovementioned keywords for category and order are supported.

  • Keyword matching is case insensitive, e.g sort Name Desc will work the same as sort name desc.

  • Either one or both of the optionals fields are to be provided.

  • Order of the input fields is not significant, e.g. sort name asc will work the same as sort asc name.

  • If order is not specified, default sort order is ascending.

  • If category is not specified, default sort category is by name.

Examples:

  • sort date - Sorts records by date in ascending order.

  • sort desc - Sorts records by name in descending order.

  • sort moneyflow desc - Sorts records by moneyflow in descending order.

5. Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

5.1. Auto Complete Feature

5.1.1. Current Implementation

The autocomplete mechanism is facilitated by the NewAutoCompletionBinding class. It represents the binding of the autocomplete window to the CommandBox and is the component that manages the interactions between the text input and the contents of the autocomplete list that is displayed in the window. This feature observes the text input in the CommandBox and displays a list of words in another window under the CommandBox for the user to select and complete his current focus text - the word he is currently typing.

The key components in this class are the autoCompletionPopup and the caretChangedListener that perform the key functionalities.

caretChangedListener is an observer that checks the caret in the command box and is triggered whenever the caret changes its position, whether a character is typed or the caret is moved using the arrow keys. When triggered, it reads the text in the command box and checks the position of the caret, then extracts the current word of target to be completed as well as the current input text and the prefix of the current word if any. Extraction is done by tracing back from the caret position and as well as tracing forward. Any characters that are not a whitespace and are not separated by a whitespace are considered to be the same word as the current word to be completed. The text before and after the word to completed are also saved so they will not be lost upon completion.

This listener passes the extracted String input to the CustomSuggestionProvider through updateSuggestions.

CustomSuggestionProvider reads the word to be competed and the input text. It trims and splits the input text and find the index of the word to completed. It reads the first input first as it is the key command word and performs a different operation on the input string depending on the command word as well as any possible following parameters.

Functions which are supported by autocomplete will parse the input individually through the different private methods available in CustomSuggestionProvider. Once it has decided which set of texts to be the new word suggestion bank, it calls the CustomSuggestionProvider#updateSuggestions overloaded method to update the SuggestionProvider.

After updating the SuggestionProvider, NewAutoCompletionBinding#SetUserInput calls onUserInputChanged which is responsible for updating the suggestions list according to what the word to be completed is. As this class was tweaked from the library implementation, the threading involved in this method will not be detailed. It updates the list of suggestions by comparing the user input word to the list of suggestions and passes the resultant list to the autoCompletionPopup which will proceed to display the list of text in the popup below the command box.

Now back to the autoCompletionPopup, whenever the user highlights a selected word input and selects it, the autoCompletionPopup#setOnSuggestion is triggered and will try to complete the word with the selected text and once completed, it hides the popup and sets the caret to the end of the newly completed word.

The following sequence diagram shows how the auto completion operation works:

AutoCompleteSequenceDiagram

5.1.2. Design Considerations

Aspect: Method to Update Suggestion Bank to use for comparison to input word
  • Alternative 1 (current choice): Use listeners to the caret in the command box

    • Pros: Accurate parsing of input and able to detect which word is currently in focus.

    • Cons: Difficult to correctly parse text, as need to avoid whitespaces. Also led to many index array exceptions that can occur when checking the input.

  • Alternative 2: Use text listeners in the command box

    • Pros: Simple to implement, similar to library implementation. Safe and minimal room for errors.

    • Cons: Cannot autocomplete by word, can only complete the last word input in the command box. Unable to perform completion for texts before the last word.

Aspect: Method to compare input word to Suggestion Bank to obtain displayed list of words
  • Alternative 1 (current choice): Check if suggestion bank word begins with input word

    • Pros: Simple, straightforward autocomplete for users. Users that are already good at typing and spelling will have a breeze using this implementation.

    • Cons: Smaller range of completion texts as users need to accurately type the first few letters before getting a an expected completion suggestion.

  • Alternative 2: Check if suggestion bank word contains input word e.g type tag → suggests findtag

    • Pros: User can type whichever word is convenient to them to obtain a suggestion they desire. Users who may not know the full spelling of a word and only partially will enjoy this.

    • Cons: Range of texts displayed may be excessive and not appealing to all users.

5.2. Find records by tag feature

5.2.1. Current Implementation

The findtag mechanism is also facilitated by ModelManager. FindTagCommand calls ModelManager#updateFilteredRecords and passes in different predicates depending on the input by the user.

This feature has only one keyword findtag and a single working mode which takes in any number of input arguments. The input given by the user is passed to FindTagCommandParser#parse to split the desired tags the user wants to search by into an array of strings. The array of strings is passed into TagsContainsKeywordsPredicate to create the predicate for updateFilteredRecordList required in ModelManager.

In TagsContainsKeywordsPredicate, to compare for a match, every keyword in the array is compared against the set of tags of each record and as long as any tag matches any of the keywords, the predicate will evaluate to true and allows the FilteredList to filter out the records that do not fulfil the predicate.

FindTagCommandParser returns a FindTagCommand object which calls updateFilteredRecordList to set the new predicate and obtain a new filteredRecords based on the predicate, which will also trigger an event for the UI to read in and display the new records.

The following sequence diagram shows how the limit operation works:

width:800

5.3. Sort records feature

5.3.1. Current Implementation

The sort mechanism is facilitated by ModelManager. It extends FinancialPlanner with a component that sorts the internal list of records. SortCommand calls ModelManager#sortFilteredRecordList and passes in the category to be sorted by and the sort order.

This feature has one keyword sort and takes in arguments of either category or order of sort. Keywords are not case sensitive.

Category can be either of the following keywords: name, date, money, moneyflow

Order can be either of the following keywords: desc - descending, asc - ascending

This feature has 2 different kind of modes as follows:

  1. Single Argument Mode - Input argument can be either the category or the order of sort

    • If category specified, records are sorted in ascending order of that category

    • If order specified, records will be sorted by name in the specified order

  2. Duo Argument Mode - Input arguments must contain only 1 category and only 1 order, and can be input in no particular order

The input given by the user is passed to SortCommandParser to split the input separated by whitespaces to ensure there is either only one or two arguments input by the user. These arguments are stored in an array of strings and the size of the array determines the mode of the command.

The strings are compared to two sets of strings containing the supported categories and orders of the function. The string of the category and a boolean representing whether the records are to be reversed will then be passed to ModelManager to sort the records.

Since the displayed list in the UI is a FilteredList which is a wrapper for the underlying list UniqueRecordList structure, sorting the internal list of records in versionedFinancialPlanner will post an event that notifies the UI to update the displayed list.

The following sequence diagram shows how the sort operation works:

width:800

5.3.2. Design Considerations

Aspect: Method of sorting data
  • Alternative 1 (current choice): Sort the observable array list in the underlying data structure in UniqueRecordList

    • Pros: Easy to implement, sorting will be permanent, user need not sort again with every following command

    • Cons: Not very intuitive, user may not have intended to modify the underlying data arrangement instead only want to sort the data just this once for viewing

  • Alternative 2: Sort the FilteredList of records obtained after filtering the underlying array list

    • Pros: Does not allow the user to alter the arrangement of the underlying data, and only obtains a sorted version of the read only data.

    • Cons: Unable to sort a FilteredList as it does not support it, implementations could instead use SortedList but it will not be able to perform the filtering function