Skip to content

Commit

Permalink
Merge pull request #215 from tiuweehan/edit-from-gui
Browse files Browse the repository at this point in the history
GUI features and Bug Fixes
  • Loading branch information
tiuweehan authored Nov 5, 2019
2 parents 3b9a27f + 337122e commit 3433dd6
Show file tree
Hide file tree
Showing 84 changed files with 2,840 additions and 238 deletions.
177 changes: 153 additions & 24 deletions docs/DeveloperGuide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@ 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.
The rest of the App consists of five components.

* <<Design-Ui,*`UI`*>>: The UI of the App.
* <<Design-Logic,*`Logic`*>>: The command executor.
* <<Design-Logic,*`UiLogic`*>>: The UI action handler.
* <<Design-Model,*`Model`*>>: Holds the data of the App in-memory.
* <<Design-Storage,*`Storage`*>>: Reads data from, and writes data to, the hard disk.

Each of the four components
Each of the five components

* Defines its _API_ in an `interface` with the same name as the Component.
* Exposes its functionality using a `{Component Name}Manager` class.
Expand All @@ -69,6 +70,11 @@ The _Sequence Diagram_ below shows how the components interact with each other f
.Component interactions for `delete 1` command
image::ArchitectureSequenceDiagram.png[]

The _Sequence Diagram_ below shows how the components interact with each other for the scenario where the user switches tabs in the GUI.

.Component interactions for Switching Tab UI Action
image::ArchitectureSequenceDiagram1.png[]

The sections below give more details of each component.

//@@author jiayushe
Expand Down Expand Up @@ -115,6 +121,30 @@ image::DeleteSequenceDiagram.png[]
NOTE: The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
//@@author

//@@author tiuweehan
[[Design-UiLogic]]
=== UiLogic Component

.Structure of the UiLogic Component
image::UiLogicClassDiagram.png[width="65%"]

*API* :
link:{repoURL}/src/main/java/seedu/algobase/ui/action/UiLogic.java[`UiLogic.java`]

. Performing an action (e.g. switching tabs) triggers the creation of a `UiActionDetails` object.
. `UiLogic` uses the `AlgoBaseUiActionParser` class to parse the `UiActionDetails` object.
. This results in a `UiAction` object which is executed by the `UiLogicManager`.
. The command execution can affect the `Model` (e.g. deleting a problem).
. The result of the command execution is encapsulated as a `UiActionResult` object which is passed back to the `Ui`.
. In addition, the `UiActionResult` object can also instruct the `Ui` to perform certain actions, such as displaying the results as feedback to the user.

.Interactions Inside the UiLogic Component for a `UiActionDetails` with a `UiActionType` of `editPlanUiAction`. This `UiActionDetails` also contains the ID of the problem to be deleted, in this case `11b`.
image::EditSequenceDiagram.png[]

NOTE: The lifeline for `EditProblemUiActionParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

//@@author

//@@author le0tan
[[Design-Model]]

Expand Down Expand Up @@ -154,8 +184,9 @@ image::design/model/ProblemSearchRulePackageDiagram.png[width="60%"]
.Structure of the PlanSearchRule Package
image::design/model/PlanSearchRulePackageDiagram.png[width='60%']

.Structure of the GUI Package
image::design/model/GuiPackageDiagram.png[width='60%']
// end::model[]

//@@author

//@@author jiayushe
Expand Down Expand Up @@ -506,71 +537,169 @@ Since AlgoBase is forked from AddressBook 3, it also inherits AB3's design choic
//@@author

//@@author tiuweehan
// tag::switchTab[]

// tag::gui
=== GUI Enhancements

An intuitive GUI facilitates the overall user friendliness of the application. The user should be able to navigate around the application easily to facilitate a smooth experience using AlgoBase. Additionally, multitasking is important as a user may be tackling multiple algorithmic questions at a single time. One of the main enhancements that we introduced to the GUI is tabbing, which fulfils these 2 requirements.
An intuitive GUI facilitates the overall user friendliness of the application.
The user should be able to navigate around the application easily to facilitate a smooth experience using AlgoBase.
While the command line is fast for typing short commands, it us not ideal if the user is editing large amounts of text (e.g. when the user is adding description for a new problem).
In this case, having a GUI will be more beneficial to the user and facilitates a smoother user experience.

==== Current Implementation
Additionally, multitasking is important as a user may be tackling multiple algorithmic questions at a single time.
This, we introduced tabbing, which facilitates multitasking in AlgoBase, which is an important requirement for competitive programmers.

==== Editing Problems from GUI

===== Current Implementation

When the user makes a change in the GUI, the change is propagated from `Ui` to `UiLogic` to `Model` and to `Storage`, as represented in the diagram below.

.An example of a high level representation of GUI actions.
image::ArchitectureSequenceDiagram1.png[]

The following classes facilitate the handling of GUI actions:

* `UiActionType` - An enum of the types of UI actions that exist in AlgoBase.
* `UiActionDetails` - An object containing details of a UI action.
* `UiAction` - Interface with instructions for executing a UI action.
* `UiLogicManager` - Manages the overall UI Logic.
* `AlgoBaseUiActionParser` - Parses a `UiActionDetails` object into an implementation of `UiAction`.
* `UiActionResult` - The result of executing the UI action.

When the user performs any action in the GUI (e.g. Editing a problem), a `UiActionDetails` object is created with a given `UiActionType`, an enum type.
This object contains information about the action which will later be used to make changes to the application.

This `UiActionDetails` object is sent to the `AlgoBaseUiActionParser`, which instantiates a `UiParser` depending on the `UiActionType` of the object.
The purpose of the `UiParser` is to convert the `UiActionDetails` object into a `UiAction` object.

The `UiAction` object stores the instructions to make the specified changes to the `Model`, which will run when its `execute` method is called.
The `UiAction` object is passed along to the `UiLogicManager`, which calls its `execute` method on the `Model` object.

This process is captured by the example in the Sequence Diagrams below.

.Interaction between `UI` and `UiLogic`
image::gui/EditProblemUiActionSequenceDiagram0.png[]

Step 1: The user edits the `ProblemDetails` controller class through his/her actions in the GUI.

Step 2: The `ProblemDetails` class constructs a new `UiActionDetails` object with using `UiActionType.EditProblem`.

Step 3: The `executeUiAction` of the `MainWindow` class is called with the `UiActionDetails` object,
which in turn calls the `execute` method of `UiLogicManager`.

Step 4: The method call returns a `UiActionResult` object, which may optionally contain feedback for the user.

The state of the GUI is stored in a `GuiState` object. The `GuiState` object contains a `TabManager` object, which manages tab information such as the tabs that are open and the tabs that are currently selected.
The following diagram goes into more details on how the `UiLogic` handles the `UiActionDetails`

.Interactions between classes in the `UiLogic`
image::gui/EditProblemUiActionSequenceDiagram1.png[]

Step 1: The `UiLogicManager` passes the `UiActionDetails` object to the `AlgoBaseActionParser`,
which in turn passes it to the `EditProblemUiActionParser` based on its Action type.

Step 2: The `EditProblemUiActionParser` converts the `UiActionDetails` object into a `EditProblemUiAction` object,
and passes it back to the `UiLogicManager`.

Step 3: The `UiLogicManager` executes the `EditProblemUiAction` together with the `Model`, and returns the `CommandResult`.

===== Design Considerations

[width="100%",cols="33%,<33%,<33%",options="header",]
|=======================================================================
|Aspect| Alternative 1 (Current Choice) | Alternative 2
| Handling Commands and UI Actions |
Handle Commands and UI Actions separately.

**Pros**: Higher modularity. Allows separation the different architectures as well
(Synchronous for Commands & Event-Driven for UI Actions)

**Cons**: Multiple Logic managers (LogicManager and UiLogicManager)
|
Handle Commands and UI Actions together.

**Pros**: Less code and higher reusability.

**Cons**: Higher coupling and less cohesion.
| Handling different kinds of UI Actions |
Using a command structure with a central parser and many smaller parsers.

**Pros**: Higher extensibility, easier to add new UI Actions

**Cons**: Have to write more code to achieve the same functionality.
|

Handling each UI action individually.

**Pros**: Can write less code to achieve the same functionality.

**Cons**: Lower extensibility, harder to add new UI Actions
|
|=======================================================================

==== Tabbing Feature

===== Current Implementation

The state of the GUI is stored in a `GuiState` object, which is in turn stored in the `Model`. The `GuiState` object contains a `TabManager` object, which manages tab information such as the tabs that are open and the tabs that are currently selected.

The information is linked to the `UI` through listeners. When the attributes of the `TabManager` object is updated, it triggers callback functions in the UI controllers that update the state of the UI displayed.

The following class diagram illustrates how the classes in the `GuiState` interact with one another:

.Class Dagram for the `GuiState` class
image::design/model/GuiPackageDiagram.png[width='60%']

The following commands facilitate the management of tabs:

* `AlgoBase#switchTab()` - Switch between tabs within a specified Tab pane.
* `AlgoBase#openTab()` - Opens a new tab containing details of a model.
* `AlgoBase#closeTab()` - Closes an existing tab.
* `switchTab` - Switch between tabs within a specified Tab pane.
* `openTab` - Opens a new tab containing details of a model.
* `closeTab` - Closes an existing tab.

These operations are exposed in the `TabManager` class respectively as:

* `SwitchTab()`: `TabManager#setDisplayTabIndex` and `TabManager#setDetailsTabIndex`
* `OpenTab()`: `TabManager#addTab`
* `CloseTab()`: `TabManager#removeTab`
* `SwitchTab`: `TabManager#switchTab`
* `OpenTab`: `TabManager#openTab`
* `CloseTab`: `TabManager#closeTab`

The following Activity Diagrams illustrate what happens when the user executes a `SwitchTabCommand` or `OpenTabCommand`

.Activity Diagram for the Execution of `switchtab` Command
image::gui/SwitchTabCommandActivityDiagram.png[width="50%"]
_Figure 1.1 Activity Diagram for the Execution of `switchtab` Command_

.Activity Diagram for the Execution of `opentab` Command
image::gui/OpenTabCommandActivityDiagram.png[width="50%"]
_Figure 1.2 Activity Diagram for the Execution of `opentab` Command_

Given below is an example usage scenario and how the tag mechanism behaves at each step.

.Sequence Diagram for instantiating a `SwitchCommand` object
image::gui/SwitchTabsSequenceDiagram0.png[]
_Figure 2.1 Sequence Diagram for instantiating a `SwitchCommand` object_

Step 1: The user executes `switchtab tt/display i/1` to switch to the first tab in the `display` tabpane.

Step 2: `SwitchTabCommandParser` processes the user input, retrieving the tab type (`display`) and the index (`1`).

Step 3: These two attributes are passed into the constructor of a `SwitchTabCommand` and a corresponding `SwitchTabCommand` object is returned to the LogicManager


.Sequence Diagram for updating the tab index in the TabManager
image::gui/SwitchTabsSequenceDiagram1.png[]
_Figure 2.2 Sequence Diagram for updating the tab index in the TabManager_

Step 4: `LogicManager` invokes `execute()` method of the returned `SwitchTabCommand`, which retrieves the TabManager from the `Model` object. The `setDisplayTabPaneIndex(1)` method is invoked with the index 1 that the `SwitchTabCommand` was instantiated with.

Step 5: Invoking this method updates the integer value in the `displayTabIndex` field (type `ObservableIntegerValue`) of the `TabManager`.


.Sequence Diagram for reflecting the tab changes
image::gui/SwitchTabsSequenceDiagram2.png[]
_Figure 3.3 Sequence Diagram for reflecting the tab changes_

Step 6: A listener was added to the `displayTabIndex` field when the application was initialized. When a change in the value is detected, it triggers the `selectTab(1)` method with the value of the new index passed as an argument. This updates the selected tab in the UI.

.Sequence Diagram for storing new GUI state
image::gui/SwitchTabsSequenceDiagram3.png[]
_Figure 3.4 Sequence Diagram for storing new GUI state_

Step 7: After the command is executed, the state of the GUI changes. This causes the `StorageManager` to save the modified GUI state as a new `JSON` file.
This is done with the help of the `JsonSerializableGui`, `JsonSerializableTabManager` and `JsonSerializableTab` classes that are wrappers for the `GuiState`, `TabManager` and `TabData` classes.
These wrapper classes can be converted into `JSON` format for storage without any data loss.

==== Design Considerations
===== Design Considerations

[width="100%",cols="33%,<33%,<33%",options="header",]
|=======================================================================
Expand Down Expand Up @@ -602,7 +731,7 @@ Updating the UI synchronously
|
|=======================================================================

// end::switchTab[]
// end::gui[]
//@@author

//@@author Seris370
Expand Down
75 changes: 58 additions & 17 deletions docs/UserGuide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -449,63 +449,104 @@ Examples:

* `setplan 10`

=== Editing from GUI

AlgoBase currently supports editing Problems and Plans from the GUI with an intuitive layout.

==== Editing a Problem / Plan

.Plan with name "Data Structures" is opened.
image::gui/EditPlanUiAction0.png[width="70%"]

Step 1: Select the problem / plan you want to delete by double clicking on it.

.The name and start date of the plan are modified.
image::gui/EditPlanUiAction1.png[width="70%"]

Step 2: Make changes to the problem / plan by editing the fields directly.

.The plan is successfully edited.
image::gui/EditPlanUiAction2.png[width="70%"]

Step 3: Save changes to the problem by clicking on the _"Edit Problem"_ / _"Edit Plan"_ button.


==== Deleting a Problem / Plan

.Problem with name "Sequences" is opened.
image::gui/DeleteProblemUiAction0.png[width="70%"]

Step 1: Select the problem / plan you want to delete by double clicking on it.

.Warning Dialog to confirm problem being deleted.
image::gui/DeleteProblemUiAction1.png[width="70%"]

Step 2: Click on the red _"Delete Problem"_ / _"Delete Plan"_ button at the bottom right.

Step 3: For _Problems_, select whether you want the problem to be removed from all existing plans.

.The problem is successfully deleted.
image::gui/DeleteProblemUiAction2.png[width="70%"]

Step 4: Click on _Confirm_.

=== Tabs

There are 2 types of tabs in AlgoBase: Display and Details tabs, as seen in the figure below.

.Types of tabs highlighted in Orange
image::gui/TabsOverview.png[width="70%"]
_fig 3.7.0 – Types of Tabs highlighted in Orange_

There are 2 types of tabs in AlgoBase: Display and Details tabs.

* **Display tabs** give a high level overview of the contents of a list of items
(e.g. a list of `problems`/`tags`/`plans`).
(e.g. a list of _problems_ / _tags_ / _plans_ / _findrules_).
* **Details tabs** give a more detailed description of an item in a display tab.

In the example in fig 3.7.0, there is a problem called "Sequences" in the current display tab.
The details for this problem can be seen in the details tab where the orange arrow is pointing to.

==== Switching Tabs: `switchtab`

.Demonstration of the `SwitchTab` command
image::gui/SwitchTabCommand.png[width="70%"]
_fig 3.7.1 – Demonstration of `SwitchTab` command_

Switches between tabs in the GUI +
Format: `switchtab tt/TAB_TYPE i/TAB_INDEX`
Format: `switchtab tt/TAB_TYPE i/TAB_INDEX` +
Format: `st tt/TAB_TYPE i/TAB_INDEX`

* Tab Type
** can be `display` or `details`
** Alternatively, `display` and `details` can be replaced by `1` and `2` respectively
** can be **display** or **details**
** Alternatively, **display** and **details** can be replaced by **1** and **2** respectively

Examples:

* `switchtab tt/display i/3` – Switches to the third **display** tab (i.e. `plans` tab), as seen in fig 3.7.1
* `switchtab tt/display i/3` – Switches to the third **display** tab (i.e. _plans_ tab).
* `st tt/1 i/3` – Same effects as the previous command but in a shorter format.
* `switchtab tt/details i/3` – Switches to the third **details** tab
* `st tt/2 i/3` – Same effects as the previous command but in a shorter format.


==== Opening Tabs: `opentab`

.Demonstration of the `OpenTab` command
image::gui/OpenTabCommand.png[width="70%"]

Opens a new **Details** tab in the GUI +
Format: `opentab m/MODEL_TYPE i/MODEL_INDEX`
Format: `opentab m/MODEL_TYPE i/MODEL_INDEX` +
Format: `ot m/MODEL_TYPE i/MODEL_INDEX`


* Model Type
** can be `problem`, `tag`, `plan` and `findrule`
** Alternatively, `problem`, `tag`, `plan` and `findrule` can be replaced by `1`, `2`, `3` and `4` respectively
** can be _problem_, _tag_, _plan_ and _findrule_
** Alternatively, _problem_, _tag_, _plan_ and _findrule_ can be replaced by _1_, _2_, _3_ and _4_ respectively

Examples:

* `opentab m/problem i/2` – Opens the 2nd problem in the list of problems, as seen in fig 3.7.2
* `opentab m/problem i/2` – Opens the 2nd problem in the list of problems.
* `ot m/1 i/2` – Same effects as the previous command but in a shorter format.
* `opentab m/plan i/3` – Opens the 3nd plan in the list of plans, as seen in fig 3.7.2
* `opentab m/plan i/3` – Opens the 3nd plan in the list of plans.
* `ot m/3 i/3` – Same effects as the previous command but in a shorter format.

==== Closing Tabs: `closetab`
Closes a **details** tab in the GUI +
Format: `closetab i/DETAILS_TAB_INDEX`
Format: `closetab i/DETAILS_TAB_INDEX` +
Format: `ct i/DETAILS_TAB_INDEX`

Examples:
Expand Down
Loading

0 comments on commit 3433dd6

Please sign in to comment.