From 5c9199a03a1c44d3c844ee81a012623814f82dcf Mon Sep 17 00:00:00 2001 From: Wang Zihan Date: Tue, 14 Nov 2023 01:06:36 +0800 Subject: [PATCH] Bug fix and add diagrams for list event - Fix a bug that the events in the event list window are not sorted - Add activity and sequence diagrams for `list events` command --- docs/DeveloperGuide.md | 24 +++- ...gram.puml => AddEventSequenceDiagram.puml} | 2 +- .../event/ListEventsActivityDiagram.puml | 28 +++++ .../event/ListEventsSequenceDiagram.puml | 114 ++++++++++++++++++ docs/team/larrywang0701.md | 3 + src/main/java/seedu/address/logic/Logic.java | 2 + .../seedu/address/logic/LogicManager.java | 5 + .../logic/commands/ListEventCommand.java | 2 +- src/main/java/seedu/address/model/Model.java | 20 ++- .../seedu/address/model/ModelManager.java | 15 ++- .../java/seedu/address/ui/MainWindow.java | 2 +- .../logic/commands/AddPersonCommandTest.java | 8 +- 12 files changed, 210 insertions(+), 15 deletions(-) rename docs/diagrams/event/{EventSequenceDiagram.puml => AddEventSequenceDiagram.puml} (97%) create mode 100644 docs/diagrams/event/ListEventsActivityDiagram.puml create mode 100644 docs/diagrams/event/ListEventsSequenceDiagram.puml diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 7ae4af75010..af8b0e73cf0 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -401,12 +401,16 @@ The following activity diagram summarizes what happens when the `DeleteNoteComma This feature allows users to add and remove `Event` to any `Person` in the contact list. It provides an easy way for users to keep track of events with the contacts. #### Overview: Event: -The adding and removing of `Event` begins with the parsing of the `AddEventCommand` and `DeleteEventCommand` using the `AddEventCommandParser` and `DeleteEventCommandParser` respectively. -The `AddEventCommand` and `DeleteEventCommand` will then be constructed and executed by the `Model`. +The adding, listing and removing of `Event` begins with the parsing of the `AddEventCommand`, `ListEventCommand` and `DeleteEventCommand` using the `AddEventCommandParser`, `ListEventCommandParser` and `DeleteEventCommandParser` respectively. +The `AddEventCommand`, `ListEventCommand` and `DeleteEventCommand` will then be constructed and executed by the `Model`. The activity diagram below shows the action sequence of adding an `Event` to a contact. - + + +The activity diagram below shows the action sequence of listing events by executing `list events` command. + + @@ -454,6 +458,20 @@ The following activity diagram summarizes what happens when `AddEventCommand` is +##### Implementing `ListEventCommand` +`ListEventCommand` extends from the abstract class `ListCommand`, +inheriting `list` as the primary command word and having `events` as its secondary command word. +It internally stores `filterStartTime`, `filterEndTime` (both can be null if filtering is not used) and `sortAscending` which are given by the [parser](#implementing-addeventcommandparser). + +When the command is executed, it carries out the following operations: +1. Using the `filterStartTime` and `filterEndTime` to filter all events in the global event list, or set the filter to always returns `true` if both `filterStartTime` and `filterEndTime` is null (in order to show the full event list to the user) +2. Sort the filtered event list in ascending or descending order based on `sortAscending` +3. Lastly a `CommandResult` with the filtered-sorted event list in String and with `listEvent = true` to tell `MainWindow` to show the event list window. + +The following activity diagram summarizes what happens when user executes `list events` from UI. + + + ##### Implementing `DeleteEventCommand` `DeleteEventCommand` extends from the abstract class `DeleteCommand`, inheriting `delete` as the primary command word and having `event` as its secondary command word. diff --git a/docs/diagrams/event/EventSequenceDiagram.puml b/docs/diagrams/event/AddEventSequenceDiagram.puml similarity index 97% rename from docs/diagrams/event/EventSequenceDiagram.puml rename to docs/diagrams/event/AddEventSequenceDiagram.puml index dc7ae46e0f6..42c238dea42 100644 --- a/docs/diagrams/event/EventSequenceDiagram.puml +++ b/docs/diagrams/event/AddEventSequenceDiagram.puml @@ -38,7 +38,7 @@ activate AddEventCommandParser AddEventCommandParser -> AddCommandParser deactivate AddEventCommandParser -AddCommandParser -> AddEventCommandParser : parse(commandText) +AddCommandParser -> AddEventCommandParser : parse(args) activate AddEventCommandParser create AddEventCommand diff --git a/docs/diagrams/event/ListEventsActivityDiagram.puml b/docs/diagrams/event/ListEventsActivityDiagram.puml new file mode 100644 index 00000000000..0f9184ad645 --- /dev/null +++ b/docs/diagrams/event/ListEventsActivityDiagram.puml @@ -0,0 +1,28 @@ +@startuml +skin rose +skinparam ActivityFontSize 15 +skinparam ArrowFontSize 12 +start +:User executes list event command; + +if () then ([both exist -st and -et argument or neither exists -st nor -et argument]) + if () then ([exist -st argument]) + if() then([valid start time and end time]) + :Filter the event based on start and end time; + else ([else]) + :Throw CommandException; + endif + else ([else]) + endif + if () then ([exists -descending argument]) + :Sort events in descending order; + else ([else]) + :Sort events in ascending order; + endif + :Returns Result message; + :Open a new window to display the event list; +else ([else]) + :Throw CommandException; +endif +stop +@enduml diff --git a/docs/diagrams/event/ListEventsSequenceDiagram.puml b/docs/diagrams/event/ListEventsSequenceDiagram.puml new file mode 100644 index 00000000000..1fc882f3bd4 --- /dev/null +++ b/docs/diagrams/event/ListEventsSequenceDiagram.puml @@ -0,0 +1,114 @@ +@startuml +!include ../style.puml +skinparam ArrowFontStyle plain + +box UI UI_COLOR_T1 +participant ":MainWindow" as MainWindow UI_COLOR +participant ":EventListWindow" as EventListWindow UI_COLOR +end box + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":ListCommandParser" as ListCommandParser LOGIC_COLOR +participant ":ListEventCommandParser" as ListEventCommandParser LOGIC_COLOR +participant ":ListEventCommand" as ListEventCommand LOGIC_COLOR +participant "commandResult:CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +-> MainWindow : executeCommand(commandText) +activate MainWindow +MainWindow -> LogicManager : execute(commandText) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(commandText) +activate AddressBookParser + +create ListCommandParser +AddressBookParser -> ListCommandParser +activate ListCommandParser + +ListCommandParser --> AddressBookParser +deactivate ListCommandParser + +AddressBookParser -> ListCommandParser : parse(commandText) +activate ListCommandParser + +create ListEventCommandParser +ListCommandParser -> ListEventCommandParser +activate ListEventCommandParser + +ListEventCommandParser -> ListCommandParser +deactivate ListEventCommandParser + +ListCommandParser -> ListEventCommandParser : parse(args) +activate ListEventCommandParser + +create ListEventCommand +ListEventCommandParser -> ListEventCommand +activate ListEventCommand + +ListEventCommand --> ListEventCommandParser +deactivate ListEventCommand + +ListEventCommandParser --> ListCommandParser +deactivate ListEventCommandParser +ListEventCommandParser -[hidden]-> ListCommandParser +destroy ListEventCommandParser + +ListCommandParser --> AddressBookParser +deactivate ListCommandParser +ListCommandParser -[hidden]-> AddressBookParser +destroy ListCommandParser + +AddressBookParser --> LogicManager +deactivate AddressBookParser + +LogicManager -> ListEventCommand : execute() +activate ListEventCommand + +ListEventCommand -> Model: updateFilteredEventList(predicate) +activate Model + +Model -> ListEventCommand +deactivate Model + +ListEventCommand -> Model: generateSortedFilteredEventList(comparator) +activate Model +ListEventCommand <- Model : sortedFilteredEventList +deactivate Model + +create CommandResult +ListEventCommand -> CommandResult +activate CommandResult + +CommandResult --> ListEventCommand : commandResult +deactivate CommandResult + +ListEventCommand --> LogicManager : commandResult +deactivate ListEventCommand +ListEventCommand -[hidden]-> LogicManager +destroy ListEventCommand + +MainWindow <-- LogicManager : commandResult +deactivate LogicManager +MainWindow --> MainWindow : handleEventList() +activate MainWindow +MainWindow --> LogicManager : getSortedFilteredEventList() +activate LogicManager +LogicManager --> Model : getSortedFilteredEventList() +activate Model +LogicManager <-- Model : sortedFilteredEventList +deactivate Model +MainWindow <-- LogicManager : sortedFilteredEventList +deactivate LogicManager +MainWindow --> EventListWindow : show(events) +activate EventListWindow +MainWindow <-- EventListWindow +deactivate EventListWindow +deactivate MainWindow +@enduml diff --git a/docs/team/larrywang0701.md b/docs/team/larrywang0701.md index 5fd54a18bdb..cf691d87bf4 100644 --- a/docs/team/larrywang0701.md +++ b/docs/team/larrywang0701.md @@ -38,6 +38,9 @@ - Wrote the User Stories part in the DG [#10](https://github.com/AY2324S1-CS2103T-W16-1/tp/pull/10) - Add details about secondary command parser in DG [#47](https://github.com/AY2324S1-CS2103T-W16-1/tp/pull/47/files#diff-1a95edf069a4136e9cb71bee758b0dc86996f6051f0d438ec2c424557de7160b) + - UML diagrams that I made: + + - #### Contributions to team-based tasks diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java index 51acb7789f7..b33bd014212 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/address/logic/Logic.java @@ -37,6 +37,8 @@ public interface Logic { /** Returns an unmodifiable view of the filtered list of events */ ObservableList getFilteredEventList(); + ObservableList getSortedFilteredEventList(); + /** * Returns the user prefs' address book file path. */ diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 8bc5ce7374a..e60a8b9e679 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -77,6 +77,11 @@ public ObservableList getFilteredEventList() { return model.getFilteredEventList(); } + @Override + public ObservableList getSortedFilteredEventList() { + return model.getSortedFilteredEventList(); + } + @Override public Path getAddressBookFilePath() { return model.getAddressBookFilePath(); diff --git a/src/main/java/seedu/address/logic/commands/ListEventCommand.java b/src/main/java/seedu/address/logic/commands/ListEventCommand.java index 314d344533b..2c55a515004 100644 --- a/src/main/java/seedu/address/logic/commands/ListEventCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListEventCommand.java @@ -62,7 +62,7 @@ public CommandResult execute(Model model) throws CommandException { result = MESSAGE_FILTERED; } result += this.sortAscending ? MESSAGE_ASCENDING : MESSAGE_DESCENDING; - List eventList = model.getSortedFilteredEventList((o1, o2) -> { + List eventList = model.generateSortedFilteredEventList((o1, o2) -> { LocalDateTime startTime1 = o1.getStartTime(); LocalDateTime startTime2 = o2.getStartTime(); return (startTime1.isBefore(startTime2) diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 84255f11295..37ddae6c58e 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -93,17 +93,27 @@ public interface Model { /** Returns an unmodifiable view of the filtered event list */ ObservableList getFilteredEventList(); + /** + * Generate a new list from sorting the filtered event list by the given {@code comparator} + * and return the generated list. + * @throws NullPointerException if {@code comparator} is null. + */ + List generateSortedFilteredEventList(Comparator comparator); + + /** + * Return the sorted-filtered-list generated + * by {@code generateSortedFilteredEventList(Comparator comparator)} + * @throws NullPointerException if {@code sorted-filtered-list} is null + * (never called {@code generateSortedFilteredEventList(Comparator comparator)} before). + */ + ObservableList getSortedFilteredEventList(); + /** * Updates the filter of the filtered event list to filter by the given {@code predicate}. * @throws NullPointerException if {@code predicate} is null. */ void updateFilteredEventList(Predicate predicate); - /** - * Get a list from sorting the filtered event list by the given {@code comparator}. - * @throws NullPointerException if {@code comparator} is null. - */ - List getSortedFilteredEventList(Comparator comparator); /** * Find a person by index. diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 605e52e84b7..2835e02c711 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -10,6 +10,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; +import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import seedu.address.commons.core.GuiSettings; @@ -31,6 +32,8 @@ public class ModelManager implements Model { private final FilteredList filteredPersons; private final FilteredList filteredEvents; + private ObservableList sortedFilteredEvents; + /** * Initializes a ModelManager with the given addressBook and userPrefs. */ @@ -149,9 +152,17 @@ public void updateFilteredEventList(Predicate predicate) { } @Override - public List getSortedFilteredEventList(Comparator comparator) { + public List generateSortedFilteredEventList(Comparator comparator) { requireNonNull(comparator); - return filteredEvents.stream().sorted(comparator).collect(Collectors.toUnmodifiableList()); + sortedFilteredEvents = FXCollections.observableList(filteredEvents.stream() + .sorted(comparator).collect(Collectors.toUnmodifiableList())); + return sortedFilteredEvents; + } + + @Override + public ObservableList getSortedFilteredEventList() { + requireNonNull(sortedFilteredEvents); + return this.sortedFilteredEvents; } @Override diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 1045c525db8..03ffc32175c 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -149,7 +149,7 @@ private void setWindowDefaultSize(GuiSettings guiSettings) { @FXML public void handleEventList() { if (!eventListWindow.isShowing()) { - eventListWindow.show(logic.getFilteredEventList()); + eventListWindow.show(logic.getSortedFilteredEventList()); } else { eventListWindow.focus(); } diff --git a/src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java b/src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java index 9cf5de17190..5c97f899ac3 100644 --- a/src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddPersonCommandTest.java @@ -170,15 +170,19 @@ public ObservableList getFilteredEventList() { } @Override - public void updateFilteredEventList(Predicate predicate) { + public List generateSortedFilteredEventList(Comparator comparator) { throw new AssertionError("This method should not be called."); } @Override - public List getSortedFilteredEventList(Comparator comparator) { + public ObservableList getSortedFilteredEventList() { throw new AssertionError("This method should not be called."); } + @Override + public void updateFilteredEventList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } @Override public Person findPersonByIndex(int index) {