diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 1f234a553c4..59e08546eed 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -154,89 +154,56 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa This section describes some noteworthy details on how certain features are implemented. -### \[Proposed\] Undo/redo feature +### \[Proposed\] Add/delete tag 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: +The proposed add/delete tag mechanism operates for both contacts and tasks in YellowBook. -* `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. +Every instance of AddTagCommand and DeleteTagCommand is created with two booleans. +For AddTagCommand, they are addTagToTask and addTagToContact. +For DeleteTagCommand, they are removeTagFromTask and removeTagFromContact. +Only one of these booleans will be true. Otherwise, an exception is thrown. -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. +Depending on the status of these booleans, an EditTaskDescriptor or EditPersonDescriptor is created respectively. -Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. +This descriptor object is then used to modify the list of tags attached to the selected task/contact. -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. +A new contact/task is created, with all attributes copied over from the original person, except for the list of tags, where the modified version is used. -![UndoRedoState0](images/UndoRedoState0.png) +This contact/task then replaces the previous contact/task in the YellowBook via `AddressBook#setPerson()`. -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. +Given below is an example usage scenario and how the add/delete tag mechanism behaves at each step. -![UndoRedoState1](images/UndoRedoState1.png) +Step 1. The user executes `addL c/1 t/CS2103T` to add the tag "CS2103T" to the first contact in the contact list. -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`. - -![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:** The above command will fail if the contact list is empty. An error message will be displayed informing the user.
-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. - -![UndoRedoState3](images/UndoRedoState3.png) +Step 2. The user now decides that adding the tag was a mistake, and decides to undo that action by executing `deleteT c/1 l/CS2103T`. -
: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 -than attempting to perform the undo. +
:information_source: **Note:** The tag provided in the `deleteL` command must be an exact match for that provided in the `addL` command. Matching is case-sensitive. Otherwise, YellowBook will display an error message stating that no such tag is present on the selected user.
The following sequence diagram shows how the undo operation works: -![UndoSequenceDiagram](images/UndoSequenceDiagram.png) +![AddTagSequenceDiagram](images/AddTagSequenceDiagram.png)
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. -
- -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. - -
: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. - -
- -Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. 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. - -![UndoRedoState5](images/UndoRedoState5.png) - -The following activity diagram summarizes what happens when a user executes a new command: - - - #### Design considerations: **Aspect: How undo & redo executes:** -* **Alternative 1 (current choice):** Saves the entire address book. - * Pros: Easy to implement. - * Cons: May have performance issues in terms of memory usage. - -* **Alternative 2:** Individual command knows how to undo/redo by - itself. - * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). - * Cons: We must ensure that the implementation of each individual command are correct. - -_{more aspects and alternatives to be added}_ - -### \[Proposed\] Data archiving +* **Alternative 1 (current choice):** Implement a static class to edit tag list. + * Pros: Preserves immutability of Contact and Task. + * Cons: Longer code, requires writing a new class. -_{Explain here how the data archiving feature will be implemented}_ +* **Alternative 2:** Use the existing EditContact and EditTask classes. + * Pros: Requires no additional code. + * Cons: Increases coupling. Will fail if the associated classes stop working. -------------------------------------------------------------------------------------------------------------------- diff --git a/docs/diagrams/AddTagSequenceDiagram.puml b/docs/diagrams/AddTagSequenceDiagram.puml new file mode 100644 index 00000000000..393bf6135b6 --- /dev/null +++ b/docs/diagrams/AddTagSequenceDiagram.puml @@ -0,0 +1,62 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":AddTagCommandParser" as AddTagCommandParser LOGIC_COLOR +participant ":AddTagCommand" as AddTagCommand LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":AddressBook" as AddressBook MODEL_COLOR +end box +[-> LogicManager : execute(addL) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(addL) +activate AddressBookParser + +create AddTagCommandParser +AddressBookParser -> AddTagCommandParser +activate AddTagCommandParser + +AddressBookParser -> AddTagCommandParser : parse(arguments) + +create AddTagCommand +AddTagCommandParser -> AddTagCommand +activate AddTagCommand + +AddTagCommand --> AddTagCommandParser +deactivate AddTagCommand + +AddTagCommandParser --> AddressBookParser +deactivate AddTagCommandParser + +AddressBookParser --> LogicManager +deactivate AddressBookParser + +LogicManager -> AddTagCommand : execute() +activate AddTagCommand + +AddTagCommand -> Model : setPerson() +activate Model + +Model -> AddressBook : setPerson() +activate AddressBook + +AddressBook --> Model : +deactivate AddressBook + +Model --> AddTagCommand +deactivate Model + +AddTagCommand --> LogicManager : result +deactivate AddTagCommand +AddTagCommand -[hidden]-> LogicManager : result +destroy AddTagCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml deleted file mode 100644 index 410aab4e412..00000000000 --- a/docs/diagrams/UndoSequenceDiagram.puml +++ /dev/null @@ -1,53 +0,0 @@ -@startuml -!include style.puml - -box Logic LOGIC_COLOR_T1 -participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR -participant "u:UndoCommand" as UndoCommand LOGIC_COLOR -end box - -box Model MODEL_COLOR_T1 -participant ":Model" as Model MODEL_COLOR -participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR -end box -[-> LogicManager : execute(undo) -activate LogicManager - -LogicManager -> AddressBookParser : parseCommand(undo) -activate AddressBookParser - -create UndoCommand -AddressBookParser -> UndoCommand -activate UndoCommand - -UndoCommand --> AddressBookParser -deactivate UndoCommand - -AddressBookParser --> LogicManager : u -deactivate AddressBookParser - -LogicManager -> UndoCommand : execute() -activate UndoCommand - -UndoCommand -> Model : undoAddressBook() -activate Model - -Model -> VersionedAddressBook : undo() -activate VersionedAddressBook - -VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook) -VersionedAddressBook --> Model : -deactivate VersionedAddressBook - -Model --> UndoCommand -deactivate Model - -UndoCommand --> LogicManager : result -deactivate UndoCommand -UndoCommand -[hidden]-> LogicManager : result -destroy UndoCommand - -[<--LogicManager -deactivate LogicManager -@enduml diff --git a/docs/images/AddTagSequenceDiagram.png b/docs/images/AddTagSequenceDiagram.png new file mode 100644 index 00000000000..dbc3412176b Binary files /dev/null and b/docs/images/AddTagSequenceDiagram.png differ diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png deleted file mode 100644 index 6addcd3a8d9..00000000000 Binary files a/docs/images/UndoSequenceDiagram.png and /dev/null differ