Collate is a simple tool for developers to consolidate the contributions of a project's authors into separate files. It is a Java desktop application that has both a Text UI and a GUI.
This guide describes the design and implementation of Collate. It will help you understand how Collate works and how you can further contribute to its development. We have organised this guide in a top-down manner so that you can understand the big picture before moving on to the more detailed sections.
- Architecture
- Text UI component
- Backend Component
- Data Component
- GUI Component
- Testing
- Future Development
Collate is made up of five main components. Users can either use Collate through the GUI
or TUI
(i.e. Text UI) components.
- The
GUI
component consists of JavaFX's FXML files which define the layout that users interact with and the Java files which control these FXML files. - The
TUI
component is an alternative of theGUI
component. Users can enter commands through the command line interface (CLI). - The
Backend
component contains all the logic needed to parse users' commands, store collated data into individual files, etc. - The
Data
component represents objects involved in the collation of source files such as the authors of the project and code snippets that were written. - The
Test Driver
component tests theTUI
,Backend
andData
components. It utilises JUnit for unit testing.
This component is the entry point for Collate if you want to use Collate through the command line without
a GUI. It consists of one class, CollateTui
and interacts with the Backend
and Data
components to generate and display the appropriate statistics.
The CollateTui
class receives commands from the command line and passes them to the Logic
class in the
Backend component to handle. CollateTui
then decides which statistics to show in the command line.
In addition to the Backend component, this class also relies on the Data component to show the
appropriate statistics.
public static void main(String[] args) {
...
Logic logic = new Logic();
...
while (!isTimeToExit) {
...
String userInput = input.nextLine();
...
output.println(handleUserInput(logic, userInput));
}
...
}
public static String handleUserInput(Logic logic, String userInput) {
switch (logic.executeCommand(userInput)) {
case COLLATE :
case SUMMARY :
return handleSummaryCommand(logic);
case VIEW :
return handleViewCommand(logic);
case EXIT :
isTimeToExit = true;
return MESSAGE_EXIT;
case INVALID :
default :
return handleInvalidCommand();
}
}
The above code snippet shows you the main method which receives a user's input and passes it to
handleUserInput()
. This process repeats continuously until an exit command is entered.
At the centre of the Backend
component is the Logic
class which is in charge of handling the execution
of user inputs from the GUI component. This component only relies on the Data component and works
independently from the GUI and TUI components.
The Logic
class contains the methods that handle the core functionality of Collate.
It can be thought of as the "brain" of Collate. User inputs are passed to the executeCommand(String)
method which parses the input to find out what type of command the input is. Finding the type of command
is done in the CommandParser
class which will be elaborated in the next section.
After knowing the type of command, Logic
executes the command and updates the its relevant fields
before calling the Storage
class to store the collated data if necessary. The data is stored in Markdown files.
More details are mentioned in the Storage
section.
The executeCommand(String)
method will then return the type of command to its caller method.
The caller method can then decide how to update the user interface.
This class provides several APIs for the user interface components (GUI and TUI) to obtain information and render them for the user.
Return type | Method and Description |
---|---|
Command.Type | executeCommand(String userInput) : Handle the execution of user inputs. |
Collection | getAuthors() : Get the authors of the project that has been collated. |
String | getTargetAuthorName() : Get the name of the target author that was specified in the |
user's view command. |
|
HashMap<SourceFile, Integer> | getTargetAuthorStatistics() : Get the statistics of the target |
author in the form of a HashMap with the keys as the SourceFile objects that the author contributed to |
|
and the values as the number of lines he/she wrote for that SourceFile . |
The CommandParser
class figures out what type of command has been entered by the user. It creates Command
objects which are then passed to Logic
to be executed.
This class plays the important role of defining the fields in each Command
object depending on the type of command.
For example, if a user enters view author1
, CommandParser
creates a Command
object that has its authorName
initialised to "author1". These fields can then be accessed by Logic
to execute the command properly.
Return type | Method and Description |
---|---|
Command | parse(String userInput) : Analyses the given userInput to determine its type and returns a |
Command object with all the relevant fields initialised. |
Storage
is a simple class that has one public method which takes in a list of lines and saves them to a
local file in a default folder. This default folder is defined in this class.
The current implementation saves collated data in Markdown files. These files are human-readable and editable, and utilises syntax from Github Flavored Markdown.
Return type | Method and Description |
---|---|
void | addCollatedFile(String fileName, ArrayList<String> collatedLines) : Saves the collatedLines |
in the default save folder with fileName as its name and .md as its extension. |
The Data component contains the classes that represent the various elements that are required in calculating contribution statistics.
Logic
manipulates these classes and the UI components will use the data within these classes to render the
display that users will see.
This class represents authors who have contributed to the project. Each Author
can have multiple
associated CodeSnippet
objects.
Each CodeSnippet
represents the lines of code between two consecutive author tags that were written by an
Author
. Since this code belongs to a file, a SourceFile
object is associated with each CodeSnippet
object.
The CodeSnippet
class has a static variable totalLines
. This variable stores the total number of
lines of code of all code snippets and is used to calculate the overall proportion of code each author wrote.
This class represents source files that contain at least one author tag. Each SourceFile
object is
constructed with the file's path relative to the user's specified folder and the file's language.
The base folder is specified through the collate from <FOLDER>
command.
> Figure 6: Structure of the GUI componentCheck out the Learning Resources page to learn more about JavaFX.
The GUI component is made up of two packages, gui
and view
. The gui
package contains the
Java files that control what users see while the view
package contains JavaFX's fxml
files that
describe how to layout JavaFX components. A stylesheet.css
is also found in the view
package.
This stylesheet customises the appearance and style of JavaFX components.
Users will enter commands through the CommandBarController
, which then passes these commands to the MainApp
.
MainApp
will then call Logic
in the Backend component to handle the actual execution of these commands.
MainApp
is then responsible for correctly displaying and updating the GUI. Collate has two views that
users can see, a Summary
view and FileStats
view which are controlled by their corresponding controller classes.
These classes will be elaborated upon in the following sections.
The MainApp
class is the main driver for the GUI component. It controls what users see and
handles user inputs by passing them to the Backend component.
MainApp
extends from JavaFX's Application
class and overrides its start
method.
This method is the starting point of the whole application and very importantly, initialises all the
components that are required for the GUI. This method also calls another method to load RootLayout.fxml
from the view
package. RootLayout.fxml
contains the information about the layout of Collate's base components.
The start
method then calls initPrimaryStage(Stage)
as seen below. This method creates a new
JavaFX Scene
using this RootLayout
and sets the main Stage
to show this scene.
private void initPrimaryStage(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle(WINDOW_TITLE);
this.primaryStage.setScene(new Scene(rootLayout));
this.primaryStage.show();
}
RootLayout.fxml
is a type of JavaFX's BorderPane
which in turn is a type of Pane
. It allows us to
layout JavaFX components by specifying which position of the BorderPane
they should appear in, be
it top, left, right, bottom or centre. The command bar where users enter commands in is positioned at the
bottom and the statistics from the collate
command is placed in the centre.
You can also customise the height and width of the window by modifying the
prefHeight
andprefWidth
parameters inRootLayout.fxml
.
When a user presses any key, MainApp
receives this information and decides what to do next. The current
implementation listens for the enter key being pressed. The enter key is used by users to express their
intent to execute the command they have typed out.
This implementation allows Collate to be extended to listen for other keystrokes such as
tab
,up
,down
, etc.
Return type | Method and Description |
---|---|
void | handleKeyPress(CommandBarController commandBarController, KeyCode key, String userInput) : |
Decides what to do when the key is entered. |
The CommandBarController
loads CommandBar.fxml
which contains a JavaFX TextField
for users to enter
commands and a JavaFX Label
which shows feedback when commands are entered.
CommandBar.fxml
, similar to RootLayout.fxml
, is a BorderPane
. The Label
is placed at the top of the
BorderPane
and the TextField
is placed in the centre.
As no preferred heights or widths are specified, JavaFX takes the default heights of the components and uses its parent container to calculate their widths. In the case of Collate, the
Label
andTextField
inherit the width ofRooyLayout.fxml
. You can read more aboutBorderPane
here.
This class has a reference to MainApp
and calls the handleKeyPress
method of MainApp
whenever a key is pressed. This ensures that the logic is handled by MainApp
to avoid unnecessary
coupling between CommandBarController
and Logic
.
Return type | Method and Description |
---|---|
void | clear() : Clear the command bar |
void | setFeedback(String feedbackText) : Set the text of the feedback label |
The SummaryController
controls the default display after entering the collate
command. It shows a
table with three columns: author's name, lines of code and proportion of code written by the author.
This class loads Summary.fxml
which is a type of StackPane
(also a type of Pane
) and contains a
TableView
. The TableView
is simply a table and rows can be added to it.
The use of
StackPane
ensures theTableView
has a maximum height and width i.e fills the space given by its parent container.
SummaryController
converts Author
objects (from the data
package) to their corresponding AuthorBean
objects and
construct rows based on certain attributes of the AuthorBean
objects.
More details of these JavaFX APIs can be found here.
The AuthorBean
class is a wrapper for the Author
class. It represents fields in the Author
class in a way
that makes it easier for the GUI to interact with.
AuthorBean
objects have several fields of Property
type. These class variables are special JavaFX constructs
which behave in a similar manner as typical Java types such as integer, double and String types. For example,
AuthorBean
has a IntegerProperty
type for its linesOfCode
variable. This variable contains an integer
which can be accessed by calling linesOfCode.get()
.
By utilising JavaFX Property
types, the GUI can interact indirectly with the Author
class to render details
in a table easily without sacrificing the semantics of the Author
class.
You can read more about JavaFX Properties here.
The FileStatsController
controls the display that is shown when a user enters the view
command.
It shows the files that the specified target author has contributed to and the proportion
of code he/she wrote in those files.
This class loads FileStats.fxml
which is a type of BorderPane
and has a Label
positioned on top and
a ListView
positioned in the centre. The Label
is used to indicate the target author's name and
the ListView
is used to show his/her contribution statistics.
This class' constructor requires a HashMap
which maps SourceFile
objects and the corresponding number
of lines the target author has written for that SourceFile
. It then uses this data to construct
FileStatsItem
objects to be shown in a ListView
.
SourceFile
is part of thedata
package and eachSourceFile
object is a representation of a source file that has been collated.
A ListView
contains objects of a certain type and these objects are laid out vertically. In this case,
the ListView
contains our custom FileStatsItem
objects. JavaFX will then render these objects as per
the layouts of the corresponding FileStatsItem
objects which will be elaborated upon in the following section.
> Figure 8: Appearance of a FileStatsItemBy creating custom objects and using
ListView
to show them, you can create complex list-based layouts.
Each FileStatsItem
object consists of nine JavaFX components.
BorderPane
- TheFileStatsItem.fxml
is aBorderPane
with aStackPane
at its center.StackPane
- The outer container which facilitates the styling of the shadow of the object.HBox card
- Forms the inner container of this custom component and lays out its children horizontally.StackPane
- Forms the container for thecircle
andpercentage
components.Shape circle
- Coloured circle behind the percentage value.Text percentage
- The text that overlays the circle.VBox
- Lays out thefilename
andlinesOfCode
verticallyText filename
Text linesOfCode
The StackPane
allows the percentage
to appear in front of the circle
. The card
HBox
component has two children, first, this StackPane
and second, the VBox
that contains the
filename
and linesOfCode
.
The
StackPane
component enables you to position elements along the z-axis while theHBox
andVBox
components enable you to position elements along the x-axis and y-axis. Together, they allow you to create your own unique custom components.
This class' constructor has a percentage parameter which is used to generate a colour for the circle
,
with green indicating a higher percentage and red indicating a lower percentage.
This class also implements Comparable
to enable sorting of FileStatsItem
objects based on their percentage values.
Collate uses JUnit to perform unit tests on the Backend, Data and TUI components. Every method is unit tested to ensure everything works as intended.
Tests are placed in the src/test
folder and if you require that actual files be used for tests, you can
place them in the src/test/testFiles
folder. Be mindful to update existing tests that rely on the current
source files within the src/text/testFiles
folder.
There are several additions that can be made to Collate to further increase its usefulness and usability.
The current implementation does not perform any tests on the GUI component and relies solely on visual feedback to ensure the user interface is showing information correctly.
By enabling users to save and load the statistics from a collate
command, users will be able to view the
progression of contributions of authors by collating at different stages of the project.
Furthermore, Collate can show a graph of contribution statistics based on these saved statistics.
Having more specific feedback to users' commands will allow users to find that what exactly happened after the command was entered. Invalid commands will show more intelligent feedback based on what the user entered.
Allowing users to press a button to auto-complete a command makes it much easier to enter commands and reduces the margin of error.
Users can traverse this history to re-execute previously typed commands. This becomes especially useful if a user wants to collate the source files in the same folder periodically.
Currently, users can only specify certain file types to be collated.