diff --git a/tutorials/ab3TracingCode.md b/tutorials/ab3TracingCode.md index 25cbf83a..86cc991f 100644 --- a/tutorials/ab3TracingCode.md +++ b/tutorials/ab3TracingCode.md @@ -291,6 +291,90 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [ {{ dg_ref }} This is a good time to read through the [**_UI component_** section of the DG](https://se-education.org/addressbook-level3/DeveloperGuide.html#ui-component) +## Misc: Tracing `Model` execution path + +1. In our previous discussions, we've primarily focused on the `Logic` component to understand the general flow of logic when executing commands. +1. Now, let's delve into how the `EditCommand#execute()` method interacts with the `Model` component. +1. Let us reproduce the full code of `EditCommand#execute()`. + + **`EditCommand#execute()`:** + ```java + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToEdit = lastShownList.get(index.getZeroBased()); + Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor); + + if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) { + throw new CommandException(MESSAGE_DUPLICATE_PERSON); + } + + model.setPerson(personToEdit, editedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson))); + } + ``` +1. We hope that you have developed an appreciation for sequence diagrams in understanding high-level overviews of AB3. + Below is a sequence diagram, with some method calls omitted for brevity, illustrating the interactions within the Model component during the execution of an edit command. + +1. Let us put a breakpoint at this line which will be the first passing of control to `Model` in `EditCommand#execute()`. + ![ModelBreakpoint](images/tracing/ModelBreakpoint.png) +1. Stepping into the Model component reveals that it returns an `FilteredList`. + +### What is `FilteredList`? + + +```java + public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) { + requireAllNonNull(addressBook, userPrefs); + + logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs); + + this.addressBook = new AddressBook(addressBook); + this.userPrefs = new UserPrefs(userPrefs); + filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); + } +``` + +1. Peeking into the constructor reveals `filteredPersons` is created with a `FilteredList` wrapped around + Addressbook's internal list. +1. `FilteredList` is a wrapper around an existing list and, as the name suggests, applies a filter to determine which elements from the original list should be included. +1. Any modifications to the original list (e.g., adding, removing, or updating elements) will be visible in the `FilteredList`. + + +### Model's `AddressBook` + + +1. Continuing on, let us step over until the next `Model` interaction, `model.hasPerson(editedPerson)`. + +setPredicate + +1. This reveals our first pass of control to `Addressbook`. +1. Upon further inspection, the `Addressbook` is merely invoking the contains method of its internal list of persons. + [Remember](#what-is-filteredlist), this is the same list that the `ModelManager`'s `FilteredList` wraps around. +1. Stepping over again brings us to `model.setPerson` which again further calls on `Addressbook` to `setPerson` as it has access to its internal list. + +### Filtering the `FilteredList` + +1. Now we should be at `model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS)`. + setPredicate +1. Stepping into this method, we see it calls `filteredPersons.setPredicate(predicate)`. +1. Predicates enable filtering the list based on specific criteria. _Hint: Another feature uses this too!_. +1. For `EditCommand`, `PREDICATE_SHOW_ALL_PERSONS` is used to clear any existing filters, + ensuring that all persons are displayed. +1. A `CommandResult` is returned with a message displaying edited `Person`. + + +How can you use what you learnt to develop a sort feature? + + ## Conclusion In this tutorial, we traced a valid edit command from raw user input to the result being displayed to the user. From this tutorial, you learned more about how the various components work together to produce a response to a user command. diff --git a/tutorials/images/tracing/EditSequenceDiagramModelHighLevel.png b/tutorials/images/tracing/EditSequenceDiagramModelHighLevel.png new file mode 100644 index 00000000..d26b2545 Binary files /dev/null and b/tutorials/images/tracing/EditSequenceDiagramModelHighLevel.png differ diff --git a/tutorials/images/tracing/EditSequenceDiagramModelHighLevel.puml b/tutorials/images/tracing/EditSequenceDiagramModelHighLevel.puml new file mode 100644 index 00000000..a1ce5c73 --- /dev/null +++ b/tutorials/images/tracing/EditSequenceDiagramModelHighLevel.puml @@ -0,0 +1,61 @@ +@startuml +!include ../style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":EditCommand" as EditCommand LOGIC_COLOR +participant "r:CommandResult" as CommandResult LOGIC_COLOR +end box + +participant "filteredPersons:FilteredList" as ObservableList MODEL_COLOR +box Model MODEL_COLOR_T1 +participant "model:ModelManager" as Model MODEL_COLOR +end box + +-> EditCommand : execute(model) +activate EditCommand + + + +EditCommand -> Model : getFilteredPersonList() +activate Model +Model --> EditCommand : filteredPersons +deactivate Model + + +EditCommand -> ObservableList : get(index) +activate ObservableList +ObservableList --> EditCommand : personToEdit +deactivate ObservableList + +EditCommand -> EditCommand : createEditedPerson(...) +activate EditCommand +EditCommand --> EditCommand: editedPerson +deactivate EditCommand + +EditCommand -> EditCommand : check for duplicates +activate EditCommand +deactivate EditCommand + +EditCommand -> Model : setPerson(...) +activate Model +Model --> EditCommand +deactivate Model + +EditCommand -> Model : updateFilteredPersonList(...) +activate Model +deactivate ObservableList +Model --> EditCommand +deactivate Model + + +create CommandResult +EditCommand -> CommandResult +activate CommandResult +CommandResult --> EditCommand +deactivate CommandResult + +[<-- EditCommand: r +deactivate EditCommand + +@enduml diff --git a/tutorials/images/tracing/ModelBreakpoint.png b/tutorials/images/tracing/ModelBreakpoint.png new file mode 100644 index 00000000..6c591c02 Binary files /dev/null and b/tutorials/images/tracing/ModelBreakpoint.png differ diff --git a/tutorials/images/tracing/ModelTracing1.png b/tutorials/images/tracing/ModelTracing1.png new file mode 100644 index 00000000..ffd1c582 Binary files /dev/null and b/tutorials/images/tracing/ModelTracing1.png differ diff --git a/tutorials/images/tracing/modelhasPerson.png b/tutorials/images/tracing/modelhasPerson.png new file mode 100644 index 00000000..e55a47de Binary files /dev/null and b/tutorials/images/tracing/modelhasPerson.png differ diff --git a/tutorials/images/tracing/setPredicate.png b/tutorials/images/tracing/setPredicate.png new file mode 100644 index 00000000..44467d8e Binary files /dev/null and b/tutorials/images/tracing/setPredicate.png differ