diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 204a91bde68..0d9269745be 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -75,7 +75,7 @@ The bulk of the app's work is done by the following four components: The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the -command `delete 1`. +command `delete NRIC`. @@ -96,8 +96,7 @@ The sections below give more details of each component. ### UI component -The **API -** of this component is specified +The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java) ![Structure of the UI Component](images/UiClassDiagram.png) @@ -122,8 +121,7 @@ The `UI` component, ### Logic component -**API -** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) +**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) Here's a (partial) class diagram of the `Logic` component: @@ -161,8 +159,7 @@ How the parsing works: ### Model component -**API -** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) +**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) @@ -186,8 +183,7 @@ The `Model` component, ### Storage component -**API -** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) +**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) @@ -374,52 +370,49 @@ The following sequence diagram shows how the New Appointment works: ![AddPatientSequenceDiagram](images/AddPatientSequenceDiagram.png) //change this -### \[Proposed\] Undo/redo feature +### Undo/redo feature -#### Proposed Implementation - -The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo -history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the -following operations: +#### Implementation -* `VersionedAddressBook#commit()`— Saves the current address book state in its history. -* `VersionedAddressBook#undo()`— Restores the previous address book state from its history. -* `VersionedAddressBook#redo()`— Restores a previously undone address book state from its history. +The proposed undo/redo mechanism is facilitated by two ArrayLists of AddressBooks stored in the Model Manager class, +which are the redoList and the undoList. Each time an action is performed, the two lists are updated accordingly +by the following three methods: -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` -and `Model#redoAddressBook()` respectively. +* `Model#updateBackup()`— Saves the current address book state in its history. +* `Model#undo()`— Restores the previous address book state by retrieving it from the undoList. +* `Model#redo()`— Restores a previously undone address book state by retrieving it from the redoList. Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. -Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the -initial address book state, and the `currentStatePointer` pointing to that single address book state. +Step 1. The user launches the application for the first time. The undoList and RedoList will both be initialised as +empty ArrayLists, and the `addressBook` instance, `ab0`, stores the current AddressBook. ![UndoRedoState0](images/UndoRedoState0.png) -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command -calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes -to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book -state. +Step 2. The user executes `delete NRIC` command to delete a person in the address book. The `delete` command +calls `Model#updateBackup()`, causing the current `addressBook` instance, `ab0`, to be added to the undoList while the +model now stores the updated address book with the deleted person, `ab1`, as the new `addressBook` instance. ![UndoRedoState1](images/UndoRedoState1.png) -Step 3. The user executes `add n/David …​` to add a new person. The `add` command also -calls `Model#commitAddressBook()`, causing another modified address book state to be saved into -the `addressBookStateList`. +Step 3. The user executes `add-patient n/David …​` to add a new patient. The `add` command also +calls `Model#updateBackup()`, causing another modified address book state to be saved into undoList, `ab1`, and the +current `addressBook` instance to be updated to the new `ab2`. ![UndoRedoState2](images/UndoRedoState2.png) -
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. +
:information_source: **Note:** If a command fails its execution, it will not call `Model#updateBackup()`, so the address book state will not be saved into the undoList.
Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing -the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` -once to the left, pointing it to the previous address book state, and restores the address book to that state. +the `undo` command. The `undo` command will call `Model#undo()`, which will add the current `addressBook` instance, +`ab2` to redoList, as well as removing the most recently added AddressBook, `ab1`, from the undoList and setting it as +the new `addressBook` instance. ![UndoRedoState3](images/UndoRedoState3.png) -
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather +
:information_source: **Note:** If the undoList is empty, then there are no previous AddressBook states to restore. The `undo` command checks if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
@@ -432,10 +425,10 @@ The following sequence diagram shows how the undo operation works:
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once -to the right, pointing to the previously undone state, and restores the address book to that state. +The `redo` command does the opposite — it calls `Model#redo()`, which restores the addressBook to its previous state +before the `undo` command. -
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo. +
:information_source: **Note:** If the redoList is empty, then there are no undone AddressBook states to restore. The `redo` command checks if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
@@ -445,13 +438,19 @@ Thus, the `addressBookStateList` remains unchanged. ![UndoRedoState4](images/UndoRedoState4.png) -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not -pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be -purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern -desktop applications follow. +Step 6. The user then decides that the person he added in step 3 was not a mistake, and executes the command `redo`. +The `redo` command will call `Model#redo()`, which will add the current `addressBook` instance, +`ab1` to undoList, as well as removing the most recently added AddressBook, `ab2`, from the redoList and setting it as +the new `addressBook` instance. Notice that the current state has been restored to the state at the end of step 3. ![UndoRedoState5](images/UndoRedoState5.png) +
:information_source: **Note:** If the number of AddressBook states stored +in the undoList reaches 5, any additional commands that makes changes to the address book will lead to the least +recently added state in the undoList to be purged as a redundant state and will no longer be accessible via `undo`. + +
+ The following activity diagram summarizes what happens when a user executes a new command: diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index 48b6cc4333c..9e87b04772b 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -8,10 +8,10 @@ Participant ":Logic" as logic LOGIC_COLOR Participant ":Model" as model MODEL_COLOR Participant ":Storage" as storage STORAGE_COLOR -user -[USER_COLOR]> ui : "delete 1" +user -[USER_COLOR]> ui : "delete NRIC" activate ui UI_COLOR -ui -[UI_COLOR]> logic : execute("delete 1") +ui -[UI_COLOR]> logic : execute("delete NRIC") activate logic LOGIC_COLOR logic -[LOGIC_COLOR]> model : deletePerson(p) diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml index 43a45903ac9..372107bbc20 100644 --- a/docs/diagrams/UndoRedoState0.puml +++ b/docs/diagrams/UndoRedoState0.puml @@ -6,16 +6,13 @@ skinparam ClassBackgroundColor #FFFFAA title Initial state -package States { - class State1 as "ab0:AddressBook" - class State2 as "ab1:AddressBook" - class State3 as "ab2:AddressBook" +package UndoList { } -State1 -[hidden]right-> State2 -State2 -[hidden]right-> State3 -hide State2 -hide State3 -class Pointer as "Current State" #FFFFFF -Pointer -up-> State1 +package RedoList { +} + +package CurrentState { + class State0 as "ab0:AddressBook" +} @end diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml index 5a41e9e1651..247d2678621 100644 --- a/docs/diagrams/UndoRedoState1.puml +++ b/docs/diagrams/UndoRedoState1.puml @@ -6,18 +6,14 @@ skinparam ClassBackgroundColor #FFFFAA title After command "delete 5" -package States <> { - class State1 as "ab0:AddressBook" - class State2 as "ab1:AddressBook" - class State3 as "ab2:AddressBook" +package UndoList { + class State0 as "ab0:AddressBook" } -State1 -[hidden]right-> State2 -State2 -[hidden]right-> State3 - -hide State3 - -class Pointer as "Current State" #FFFFFF +package RedoList { +} -Pointer -up-> State2 +package CurrentState { + class State1 as "ab1:AddressBook" +} @end diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml index ad32fce1b0b..910f01891fe 100644 --- a/docs/diagrams/UndoRedoState2.puml +++ b/docs/diagrams/UndoRedoState2.puml @@ -6,16 +6,15 @@ skinparam ClassBackgroundColor #FFFFAA title After command "add n/David" -package States <> { - class State1 as "ab0:AddressBook" - class State2 as "ab1:AddressBook" - class State3 as "ab2:AddressBook" +package UndoList { + class State1 as "ab1:AddressBook" + class State0 as "ab0:AddressBook" } -State1 -[hidden]right-> State2 -State2 -[hidden]right-> State3 - -class Pointer as "Current State" #FFFFFF +package RedoList { +} -Pointer -up-> State3 +package CurrentState { + class State2 as "ab2:AddressBook" +} @end diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml index 9187a690036..9bf01d8611d 100644 --- a/docs/diagrams/UndoRedoState3.puml +++ b/docs/diagrams/UndoRedoState3.puml @@ -6,16 +6,15 @@ skinparam ClassBackgroundColor #FFFFAA title After command "undo" -package States <> { - class State1 as "ab0:AddressBook" - class State2 as "ab1:AddressBook" - class State3 as "ab2:AddressBook" +package RedoList { + class State2 as "ab2:AddressBook" } -State1 -[hidden]right-> State2 -State2 -[hidden]right-> State3 - -class Pointer as "Current State" #FFFFFF +package UndoList { + class State0 as "ab0:AddressBook" +} -Pointer -up-> State2 +package CurrentState { + class State1 as "ab1:AddressBook" +} @end diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml index 2bc631ffcd0..636cfa22b35 100644 --- a/docs/diagrams/UndoRedoState4.puml +++ b/docs/diagrams/UndoRedoState4.puml @@ -6,16 +6,15 @@ skinparam ClassBackgroundColor #FFFFAA title After command "list" -package States <> { - class State1 as "ab0:AddressBook" - class State2 as "ab1:AddressBook" - class State3 as "ab2:AddressBook" +package RedoList { + class State2 as "ab2:AddressBook" } -State1 -[hidden]right-> State2 -State2 -[hidden]right-> State3 - -class Pointer as "Current State" #FFFFFF +package UndoList { + class State0 as "ab0:AddressBook" +} -Pointer -up-> State2 +package CurrentState { + class State1 as "ab1:AddressBook" +} @end diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml index e77b04104aa..5f32dd86374 100644 --- a/docs/diagrams/UndoRedoState5.puml +++ b/docs/diagrams/UndoRedoState5.puml @@ -6,17 +6,15 @@ skinparam ClassBackgroundColor #FFFFAA title After command "clear" -package States <> { - class State1 as "ab0:AddressBook" - class State2 as "ab1:AddressBook" - class State3 as "ab3:AddressBook" +package UndoList { + class State1 as "ab1:AddressBook" + class State0 as "ab0:AddressBook" } -State1 -[hidden]right-> State2 -State2 -[hidden]right-> State3 - -class Pointer as "Current State" #FFFFFF +package RedoList { +} -Pointer -up-> State3 -note right on link: State ab2 deleted. +package CurrentState { + class State2 as "ab2:AddressBook" +} @end diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml index 87ff3e9237e..84b2bd46b7b 100644 --- a/docs/diagrams/UndoSequenceDiagram.puml +++ b/docs/diagrams/UndoSequenceDiagram.puml @@ -10,7 +10,10 @@ end box box Model MODEL_COLOR_T1 participant ":Model" as Model MODEL_COLOR -participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR +participant ":AddressBook" as NewAddressBook MODEL_COLOR +participant "addressBook:AddressBook" as AddressBook MODEL_COLOR +participant "redoList:ArrayList" as RedoList MODEL_COLOR +participant "undoList:ArrayList" as UndoList MODEL_COLOR end box [-> LogicManager : execute(undo) activate LogicManager @@ -31,15 +34,32 @@ deactivate AddressBookParser LogicManager -> UndoCommand : execute() activate UndoCommand -UndoCommand -> Model : undoAddressBook() +UndoCommand -> Model : undo() activate Model -Model -> VersionedAddressBook : undo() -activate VersionedAddressBook +create NewAddressBook +Model -> NewAddressBook : new AddressBook(addressBook) +activate NewAddressBook -VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook) -VersionedAddressBook --> Model : -deactivate VersionedAddressBook +NewAddressBook --> Model : newAddressBook +deactivate NewAddressBook + +Model -> RedoList : add() +activate RedoList + +RedoList -> RedoList : add(newAddressBook) +RedoList --> Model +deactivate RedoList + +Model -> UndoList : remove(index) +activate UndoList +UndoList --> Model : d +deactivate + +Model -> AddressBook : resetData(d) +activate AddressBook +AddressBook --> Model +deactivate AddressBook Model --> UndoCommand deactivate Model diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 37ad06a2803..ee56e5ee8d3 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png index c5f91b58533..89b3822cd25 100644 Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png index 2d3ad09c047..3e4d39e8ed9 100644 Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png index 20853694e03..3d8315116fa 100644 Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png index 1a9551b31be..5738fdc23a3 100644 Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png index 46dfae78c94..d544943620a 100644 Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png index f45889b5fdf..630f8663adb 100644 Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png index c7a7e637266..e35b7ae97b5 100644 Binary files a/docs/images/UndoSequenceDiagram.png and b/docs/images/UndoSequenceDiagram.png differ