diff --git a/docs/AboutUs.adoc b/docs/AboutUs.adoc index 3f303c5cf..65a8e9cdb 100644 --- a/docs/AboutUs.adoc +++ b/docs/AboutUs.adoc @@ -14,7 +14,7 @@ image::seanieyap.png[width="150", align="left"] {empty}[https://github.com/seanieyap[Github]] [<>] [https://seanieyap.com[Personal Website]] Role: Team Lead, Developer + -Responsibilities: Add, Edit, list, Delete Slots +Responsibilities: Add, Edit, Delete Commands and handling of Storage. ''' @@ -23,24 +23,24 @@ image::marcus-pzj.png[width="150", align="left"] {empty}[https://github.com/marcus-pzj[Github]] [<>] Role: Developer + -Responsibilities: View, Find, Auto-Complete +Responsibilities: List, Find, Undo, Redo, History commands and Auto-Complete feature. ''' === Julian Lim -image::julianlim.png[width="150", align="left"] +image::macchazuki.png[width="150", align="left"] {empty}[https://github.com/macchazuki[Github]] [<>] Role: Developer + -Responsibilities: Encryption, Import, Export, Generate Summary +Responsibilities: Encryption, Decryption, Import, Export and Generate Summary feature. ''' === Lim Ding Heng -image::limdingheng.png[width="150", align="left"] +image::dingheng4448.png[width="150", align="left"] {empty}[https://github.com/dingheng4448[Github]] [<>] Role: Developer + -Responsibilities: Generate Day, Week, Month Views +Responsibilities: View day, week, month commands and Initialization of calendars. ''' diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index 8eeb60f9a..4a4df8ad5 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -15,7 +15,7 @@ ifdef::env-github[] :warning-caption: :warning: :experimental: endif::[] -:repoURL: https://github.com/CS2113-AY1819S2-T08-3/main/tree/master +:repoURL: https://github.com/CS2113-AY1819S2-T08-3/main/blob/master By: `T08-3` Since: `Jan 2019` Licence: `MIT` @@ -113,14 +113,14 @@ When you are ready to start coding, === Architecture .Architecture Diagram -image::Architecture.png[width="100%"] +image::Architecture.png[width="800"] The *_Architecture Diagram_* given above explains the high-level design of the App. Given below is a quick overview of each component. [TIP] The `.pptx` files used to create diagrams in this document can be found in the link:{repoURL}/docs/diagrams/[diagrams] folder. To update a diagram, modify the diagram in the pptx file, select the objects of the diagram, and choose `Save as picture`. -`Main` has only one class called link:{repoURL}/src/PlanMySem/Main.java[`Main`]. It is responsible for, +`Main` has only one class called link:{repoURL}/src/planmysem/Main.java[`Main`]. It is responsible for, * At app launch: Initializes the components in the correct sequence, and connects them up with each other. * At shut down: Shuts down the components and invokes cleanup method where necessary. @@ -142,7 +142,7 @@ Each of the four components For example, the `Logic` component (see the class diagram given below) defines it's API in the `Logic.java` interface and exposes its functionality using the `Logic.java` class. .Class Diagram of overall application. -image::OverallClassDiagram.png[width="100%"] +image::OverallClassDiagram.png[width="800"] [discrete] ==== How the architecture components interact with each other @@ -150,7 +150,7 @@ image::OverallClassDiagram.png[width="100%"] The _Sequence Diagram_ below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. .Component interactions for `delete 1` command -image::SDforDeleteSlot.png[width="100%"] +image::SDforDeleteSlot.png[width="800"] The sections below give more details of each component. @@ -160,7 +160,7 @@ The sections below give more details of each component. .Structure of the UI Component image::UiClassDiagram.png[width="800"] -*API* : link:{repoURL}/src/main/PlanMySem/ui/Ui.java[`Ui.java`] +*API* : link:{repoURL}/src/planmysem/ui/Ui.java[`Ui.java`] The UI consists of a `MainWindow` that is made up of just `commandInput` and `outputConsole`. This application is mainly a text-based application, hence here are not much componenets here. @@ -181,7 +181,7 @@ The `UI` component, image::LogicClassDiagram.png[width="800"] *API* : -link:{repoURL}/src/main/java/plamysem/logicManager/Logic.java[`Logic.java`] +link:{repoURL}/src/planmysem/logic/Logic.java[`Logic.java`] . `Logic` uses the `parser` class to parse the user command. . This results in a `Command` object which is executed. @@ -192,20 +192,20 @@ link:{repoURL}/src/main/java/plamysem/logicManager/Logic.java[`Logic.java`] Given below is the Sequence Diagram for interactions within the `Logic` component for the `execute("delete 1")` API call. .Interactions Inside the Logic Component for the `delete 1` Command -image::DeletePersonSdForLogic.png[width="800"] +image::SDforDeleteSlot.png[width="800"] [[Design-Model]] === Model component .Overall structure of the Model Component -image::ModelClassDiagram.png[width="400"] +image::ModelClassDiagram.png[width="600"] -*API* : link:{repoURL}/src/PlanMySem/model/Model.java[`Model.java`] +*API* : link:{repoURL}/src/planmysem/model/Model.java[`Model.java`] [[Design-Planner]] ==== Planner component -*API* : link:{repoURL}/src/PlanMySem/model/Planner.java[`Planner.java`] +*API* : link:{repoURL}/src/planmysem/data/Planner.java[`Planner.java`] The `Planner` component, @@ -216,7 +216,7 @@ The `Planner` component, [[Design-Semester]] ==== Semester component -*API* : link:{repoURL}/src/PlanMySem/model/semester/Semester.java[`Semester.java`] +*API* : link:{repoURL}/src/planmysem/model/semester/Semester.java[`Semester.java`] The `Semester` component, @@ -227,7 +227,7 @@ The `Semester` component, [[Design-Slot]] ==== Slot component -*API* : link:{repoURL}/src/PlanMySem/model/slot/Slot.java[`Slot.java`] +*API* : link:{repoURL}/src/planmysem/model/slot/Slot.java[`Slot.java`] The `Slot` component, @@ -244,7 +244,7 @@ Notice how `Slot` does not hold it's end time but rather it holds the `duration` .Structure of the Storage Component image::StorageClassDiagram.png[width="400"] -*API* : link:{repoURL}/src/PlanMySem/storageFile/Storage.java[`Storage.java`] +*API* : link:{repoURL}/src/planmysem/storage/Storage.java[`Storage.java`] The `Storage` component, @@ -381,10 +381,10 @@ Arguments are then parsed via 2 different methods/techniques according to the fo Hence, parameters in *PlanMySem* can be categorised into 2 categories: -1. Prepended parameters such as `n/NAME`, `st/START_TIME`, `des/DESCRIPTION`, etc. -2. Non-prepended parameters, A.K.A. keywords, such as `INDEX`, `TYPE_OF_VIEW`. etc. +1. Prefixed parameters such as `n/NAME`, `st/START_TIME`, `des/DESCRIPTION`, etc. +2. Non-Prefixed parameters, A.K.A. keywords, such as `INDEX`, `TYPE_OF_VIEW`. etc. -===== Parsing Prepended Parameters +===== Parsing Prefixed Parameters To retrieve the set of parameters, the function `private static HashMap> getParametersWithArguments(String args)` can be called. The function returns a `Hashmap` data structure, specifically `HashMap>`, to hold parameters, allowing for easy, quick and efficient access to specific parameters. @@ -398,9 +398,9 @@ The following are cases in which `IncorrectCommand` is invoked: ===== Parsing Keywords -Here, keywords are thought of as parameters that are not prepended. +Here, keywords are thought of as parameters that are not prefixed. In *PlanMySem*, keywords are utilized in command structures when they are to be used alone or when order of parameters are important. -In such cases, there is no logical need for prepending as the meaning of these parameters can be identified. +In such cases, there is no logical need for prefixing as the meaning of these parameters can be identified. The function `private String getStartingArgument(String args)` provides this functionality. Here, `IncorrectCommand` is invoked due to different circumstances: @@ -469,10 +469,38 @@ The `Edit` and `Delete` command then makes use of the _tagging_ system to then s ==== Design Considerations +===== Aspect: Wrapping of primitive data types in `Slot` +* *Alternative 1 (current choice):* Use of "primitive" data types instead of creating and utilising wrapped objects. + +E.g. `name`, `location` amd `description` are not wrapped but "primitive". +** Pros: Allows for more flexible code to account for flexible parsing (as needed in this application). +** Cons: Bigger code base and duplicated code. + +* *Alternative 2:* Wrap "primitive" data types. +** Pros: Less errors in handling invalid values. +** Cons: May cause inflexibility in writing code to account for flexible parsing. + +In summary, in this cause of *PlanMySme*, there is a need to achieve varied and flexible commands and as such, +it is not necessary to handle invalid values with the innate `Model` objects as these are taken care of when parsing. + +Additionally, doing these actions when parsing, though bloats code, allows for more varied responses to the user and improves user experience. + +===== Aspect: Storing and accessing `Slots` + +* *Alternative 1 (current choice):* Use of `Map`, such as `HashMap` to store `Days` that store `Slots`. +** Pros: `HashMap` allows for easier and faster, O(1) access time, access of particular `Day` according to date. +** Cons: This requires splitting of the calendar into days, as such there is no easy way to account for `Slots` that occur across days. + +* *Alternative 2:* Store `Slots` in a huge list. +** Pros: Allows for easier access by "index" and offers flexibility, for example, in the time of slots. +** Cons: Expensive to access, add and remove items. Furthermore, it is extremely expensive to collect slots that occur in a day, a very important and most likely to be a commonly used feature. ==== Future Implementation +===== Create and utilise an object to hold `Slots` + +===== Create and utilise an object in `Planner` to hold multiple `Semesters` + === List feature @@ -535,6 +563,84 @@ Step 3. The user executes `view month March` command to view the calendar for Ma // tag::undoredo[] === Undo/Redo feature + +==== Current Implementation + +The 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: + +* `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. + +These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. + +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. + +image::UndoRedoStartingStateListDiagram.png[width="800"] + +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. + +image::UndoRedoNewCommand1StateListDiagram.png[width="800"] + +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`. + +image::UndoRedoNewCommand2StateListDiagram.png[width="800"] + +[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`. + +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. + +image::UndoRedoExecuteUndoStateListDiagram.png[width="800"] + +[NOTE] +If the `currentStatePointer` is at index 0, pointing to the initial address book state, then there are no previous address book 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. + +The following sequence diagram shows how the undo operation works: + +image::UndoRedoSequenceDiagram.png[width="800"] + +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. + +[NOTE] +If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone address book 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. + +image::UndoRedoNewCommand3StateListDiagram.png[width="800"] + +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. We designed it this way because it no longer makes sense to redo the `add n/David ...` command. This is the behavior that most modern desktop applications follow. + +image::UndoRedoNewCommand4StateListDiagram.png[width="800"] + +The following activity diagram summarizes what happens when a user executes a new command: + +image::UndoRedoActivityDiagram.png[width="650"] + +==== 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. + +===== Aspect: Data structure to support the undo/redo commands + +* **Alternative 1 (current choice):** Use a list to store the history of address book states. +** Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project. +** Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both `HistoryManager` and `VersionedAddressBook`. +* **Alternative 2:** Use `HistoryManager` for undo/redo +** Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase. +** Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as `HistoryManager` now needs to do two different things. + ==== Current Implementation The undo/redo mechanism is facilitated by `VersionedPlanner`. diff --git a/docs/diagrams/UiComponentClassDiagram.pptx b/docs/diagrams/UiComponentClassDiagram.pptx deleted file mode 100644 index b27be3ed8..000000000 Binary files a/docs/diagrams/UiComponentClassDiagram.pptx and /dev/null differ diff --git a/docs/diagrams/UndoRedoActivityDiagram.pptx b/docs/diagrams/UndoRedoActivityDiagram.pptx index 16fec930c..dd550dde0 100644 Binary files a/docs/diagrams/UndoRedoActivityDiagram.pptx and b/docs/diagrams/UndoRedoActivityDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoExecuteUndoStateListDiagram.pptx b/docs/diagrams/UndoRedoExecuteUndoStateListDiagram.pptx index 6fd31b5f3..0ea85d12e 100644 Binary files a/docs/diagrams/UndoRedoExecuteUndoStateListDiagram.pptx and b/docs/diagrams/UndoRedoExecuteUndoStateListDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoNewCommand1StateListDiagram.pptx b/docs/diagrams/UndoRedoNewCommand1StateListDiagram.pptx index 1f3261976..ef9b09138 100644 Binary files a/docs/diagrams/UndoRedoNewCommand1StateListDiagram.pptx and b/docs/diagrams/UndoRedoNewCommand1StateListDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoNewCommand2StateListDiagram.pptx b/docs/diagrams/UndoRedoNewCommand2StateListDiagram.pptx index e2907d4a9..c54d43d3f 100644 Binary files a/docs/diagrams/UndoRedoNewCommand2StateListDiagram.pptx and b/docs/diagrams/UndoRedoNewCommand2StateListDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoNewCommand3StateListDiagram.pptx b/docs/diagrams/UndoRedoNewCommand3StateListDiagram.pptx index 4ecc659bd..8bf64034e 100644 Binary files a/docs/diagrams/UndoRedoNewCommand3StateListDiagram.pptx and b/docs/diagrams/UndoRedoNewCommand3StateListDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoNewCommand4StateListDiagram.pptx b/docs/diagrams/UndoRedoNewCommand4StateListDiagram.pptx index 16ebf585d..34cebf37b 100644 Binary files a/docs/diagrams/UndoRedoNewCommand4StateListDiagram.pptx and b/docs/diagrams/UndoRedoNewCommand4StateListDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoSequenceDiagram.pptx b/docs/diagrams/UndoRedoSequenceDiagram.pptx index 5ccc1042c..1811bc6a8 100644 Binary files a/docs/diagrams/UndoRedoSequenceDiagram.pptx and b/docs/diagrams/UndoRedoSequenceDiagram.pptx differ diff --git a/docs/diagrams/UndoRedoStartingStateListDiagram.pptx b/docs/diagrams/UndoRedoStartingStateListDiagram.pptx index 98ce06764..94b0f748c 100644 Binary files a/docs/diagrams/UndoRedoStartingStateListDiagram.pptx and b/docs/diagrams/UndoRedoStartingStateListDiagram.pptx differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 0c913eaa3..921b318b9 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/docs/images/UndoRedoActivityDiagram.png b/docs/images/UndoRedoActivityDiagram.png new file mode 100644 index 000000000..fe1ea855f Binary files /dev/null and b/docs/images/UndoRedoActivityDiagram.png differ diff --git a/docs/images/UndoRedoExecuteUndoStateListDiagram.png b/docs/images/UndoRedoExecuteUndoStateListDiagram.png new file mode 100644 index 000000000..92115701d Binary files /dev/null and b/docs/images/UndoRedoExecuteUndoStateListDiagram.png differ diff --git a/docs/images/UndoRedoNewCommand1StateListDiagram.png b/docs/images/UndoRedoNewCommand1StateListDiagram.png new file mode 100644 index 000000000..08259988e Binary files /dev/null and b/docs/images/UndoRedoNewCommand1StateListDiagram.png differ diff --git a/docs/images/UndoRedoNewCommand2StateListDiagram.png b/docs/images/UndoRedoNewCommand2StateListDiagram.png new file mode 100644 index 000000000..99571d992 Binary files /dev/null and b/docs/images/UndoRedoNewCommand2StateListDiagram.png differ diff --git a/docs/images/UndoRedoNewCommand3StateListDiagram.png b/docs/images/UndoRedoNewCommand3StateListDiagram.png new file mode 100644 index 000000000..8886946eb Binary files /dev/null and b/docs/images/UndoRedoNewCommand3StateListDiagram.png differ diff --git a/docs/images/UndoRedoNewCommand4StateListDiagram.png b/docs/images/UndoRedoNewCommand4StateListDiagram.png new file mode 100644 index 000000000..e077167a1 Binary files /dev/null and b/docs/images/UndoRedoNewCommand4StateListDiagram.png differ diff --git a/docs/images/UndoRedoSequenceDiagram.png b/docs/images/UndoRedoSequenceDiagram.png new file mode 100644 index 000000000..4693b259b Binary files /dev/null and b/docs/images/UndoRedoSequenceDiagram.png differ diff --git a/docs/images/UndoRedoStartingStateListDiagram.png b/docs/images/UndoRedoStartingStateListDiagram.png new file mode 100644 index 000000000..9f989a195 Binary files /dev/null and b/docs/images/UndoRedoStartingStateListDiagram.png differ diff --git a/docs/team/seanieyap.adoc b/docs/team/seanieyap.adoc index f2d6b2771..caad395ce 100644 --- a/docs/team/seanieyap.adoc +++ b/docs/team/seanieyap.adoc @@ -12,8 +12,7 @@ This portfolio documents my contributions to _PlanMySem_, a software engineering module project. This module was taken in my third year during the second semester. - -AddressBook - Level 4 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. +*PlanMySem* is a text-based (Command Line Interface) scheduling/calendar application that targets NUS students and staff who prefer to use a desktop application for managing their schedule/calendar. == Summary of contributions diff --git a/src/planmysem/common/Messages.java b/src/planmysem/common/Messages.java index bdd81a80c..0f6863607 100644 --- a/src/planmysem/common/Messages.java +++ b/src/planmysem/common/Messages.java @@ -82,18 +82,10 @@ public static String craftSelectedMessage(String header, return sb.toString() + getSelectedMessage(selectedSlots); } - /** - * Craft selected message without header. - */ - public static String craftSelectedMessage(Map> selectedSlots) { - return getSelectedMessage(selectedSlots); - } - /** * Craft selected message via weighted Set of Pairs. */ - public static String craftSelectedMessagePair(Set pairs) { + public static String craftListMessage(Set pairs) { StringBuilder sb = new StringBuilder(); sb.append("Here are the closest matching names/tags: \n"); diff --git a/src/planmysem/logic/Logic.java b/src/planmysem/logic/Logic.java index 024b46a66..b329f0e66 100644 --- a/src/planmysem/logic/Logic.java +++ b/src/planmysem/logic/Logic.java @@ -1,7 +1,7 @@ package planmysem.logic; import java.time.LocalDate; -import java.util.Map; +import java.util.List; import javafx.collections.ObservableList; import javafx.util.Pair; @@ -29,7 +29,7 @@ public interface Logic { /** * Gets unmodifiable view of the current last shown list. */ - Map> getLastShownSlots(); + List>> getLastShownSlots(); /** * Returns an unmodifiable view of the list of commands entered by the user. diff --git a/src/planmysem/logic/LogicManager.java b/src/planmysem/logic/LogicManager.java index 65c9ed9bd..a20df90d8 100644 --- a/src/planmysem/logic/LogicManager.java +++ b/src/planmysem/logic/LogicManager.java @@ -1,7 +1,7 @@ package planmysem.logic; import java.time.LocalDate; -import java.util.Map; +import java.util.List; import javafx.collections.ObservableList; import javafx.util.Pair; @@ -40,7 +40,7 @@ public String getStorageFilePath() { } @Override - public Map> getLastShownSlots() { + public List>> getLastShownSlots() { return model.getLastShownList(); } diff --git a/src/planmysem/logic/commands/FindCommand.java b/src/planmysem/logic/commands/FindCommand.java index 8c8e0a817..a89a0a786 100644 --- a/src/planmysem/logic/commands/FindCommand.java +++ b/src/planmysem/logic/commands/FindCommand.java @@ -98,7 +98,7 @@ public CommandResult execute(Model model, CommandHistory commandHistory) { } return new CommandResult(String.format(MESSAGE_SUCCESS, selectedNames.size(), - Messages.craftSelectedMessagePair(selectedNames))); + Messages.craftListMessage(selectedNames))); } /** @@ -117,11 +117,6 @@ private void generateDiscoveredNames(String keyword, String compareString) { //System.out.println(compareString + " vs key: " + keyword + " dist: " + dist); WeightedName distNamePair = new WeightedName(compareString, dist); - for (WeightedName weightName : weightedNames) { - if (weightName.getName().equalsIgnoreCase(distNamePair.getName())) { - return; - } - } weightedNames.add(distNamePair); } } diff --git a/src/planmysem/logic/commands/ListCommand.java b/src/planmysem/logic/commands/ListCommand.java index f335907cc..7a502b2f4 100644 --- a/src/planmysem/logic/commands/ListCommand.java +++ b/src/planmysem/logic/commands/ListCommand.java @@ -64,6 +64,7 @@ public CommandResult execute(Model model, CommandHistory commandHistory) { if (selectedSlots.isEmpty()) { return new CommandResult(MESSAGE_SUCCESS_NONE); } + model.setLastShownList(selectedSlots); return new CommandResult(String.format(MESSAGE_SUCCESS, selectedSlots.size(), diff --git a/src/planmysem/logic/commands/RedoCommand.java b/src/planmysem/logic/commands/RedoCommand.java index 34771a1a0..70c95d8e7 100644 --- a/src/planmysem/logic/commands/RedoCommand.java +++ b/src/planmysem/logic/commands/RedoCommand.java @@ -24,7 +24,7 @@ public CommandResult execute(Model model, CommandHistory history) throws Command } model.redo(); - model.setLastShownList(null); + model.clearLastShownList(); return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/planmysem/logic/commands/UndoCommand.java b/src/planmysem/logic/commands/UndoCommand.java index e27a9cb75..e74269b82 100644 --- a/src/planmysem/logic/commands/UndoCommand.java +++ b/src/planmysem/logic/commands/UndoCommand.java @@ -24,7 +24,7 @@ public CommandResult execute(Model model, CommandHistory history) throws Command } model.undo(); - model.setLastShownList(null); + model.clearLastShownList(); return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/planmysem/model/Model.java b/src/planmysem/model/Model.java index 4cd3c15ab..cdc1f2d84 100644 --- a/src/planmysem/model/Model.java +++ b/src/planmysem/model/Model.java @@ -3,6 +3,7 @@ import java.time.LocalDate; import java.time.LocalTime; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -21,8 +22,12 @@ public interface Model { /** * Set last shown list. */ + void setLastShownList(List>> list); + void setLastShownList(Map> list); + void clearLastShownList(); + /** * Saves the current planner state for undo/redo. */ @@ -31,7 +36,7 @@ public interface Model { /** * Get last shown list. */ - Map> getLastShownList(); + List>> getLastShownList(); /** * Get item in last shown list. diff --git a/src/planmysem/model/ModelManager.java b/src/planmysem/model/ModelManager.java index f31ee7a17..27c5b7cf0 100644 --- a/src/planmysem/model/ModelManager.java +++ b/src/planmysem/model/ModelManager.java @@ -2,10 +2,11 @@ import java.time.LocalDate; import java.time.LocalTime; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; import javafx.util.Pair; import planmysem.model.semester.Day; @@ -18,7 +19,7 @@ * Represents the entire Planner. Contains the model of the Planner. */ public class ModelManager implements Model { - protected Map> lastShownList = new TreeMap<>(); + protected List>> lastShownList = new ArrayList<>(); private final VersionedPlanner versionedPlanner; /** @@ -38,21 +39,37 @@ public ModelManager(ReadOnlyPlanner planner) { } @Override + public void setLastShownList(List>> list) { + lastShownList.clear(); + + if (list != null) { + lastShownList.addAll(list); + } + } + public void setLastShownList(Map> list) { lastShownList.clear(); if (list != null) { - lastShownList.putAll(list); + for (Map.Entry> entry : list.entrySet()) { + lastShownList.add(new Pair<>(entry.getKey(), entry.getValue())); + } } } + @Override + public void clearLastShownList() { + lastShownList.clear(); + } + + @Override public void commit() { versionedPlanner.commit(); } @Override - public Map> getLastShownList() { + public List>> getLastShownList() { return lastShownList; } @@ -62,17 +79,7 @@ public Pair> getLastShownItem(int ind throw new IndexOutOfBoundsException(); } - int adjustedIndex = index - 1; - - int count = 0; - for (Map.Entry> entry : lastShownList.entrySet()) { - if (count == adjustedIndex) { - return new Pair<>(entry.getKey(), entry.getValue()); - } - count++; - } - - throw new IndexOutOfBoundsException(); + return lastShownList.get(index - 1); } @Override diff --git a/src/planmysem/ui/Gui.java b/src/planmysem/ui/Gui.java index 709e6bbcc..fba5c9f73 100644 --- a/src/planmysem/ui/Gui.java +++ b/src/planmysem/ui/Gui.java @@ -18,7 +18,7 @@ public class Gui implements Ui { */ public static final int DISPLAYED_INDEX_OFFSET = 1; - public static final int INITIAL_WINDOW_WIDTH = 800; + public static final int INITIAL_WINDOW_WIDTH = 1000; public static final int INITIAL_WINDOW_HEIGHT = 600; private final LogicManager logicManager; diff --git a/test/java/planmysem/logic/Commands/AddCommandTest.java b/test/java/planmysem/logic/Commands/AddCommandTest.java index eed8e00fc..3e08ed019 100644 --- a/test/java/planmysem/logic/Commands/AddCommandTest.java +++ b/test/java/planmysem/logic/Commands/AddCommandTest.java @@ -12,6 +12,7 @@ import java.time.LocalTime; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -123,7 +124,12 @@ public void equals() throws Exception { */ private class ModelStub implements Model { @Override - public Map> getLastShownList() { + public List>> getLastShownList() { + throw new AssertionError("This method should not be called."); + } + + @Override + public void clearLastShownList() { throw new AssertionError("This method should not be called."); } @@ -132,6 +138,11 @@ public void commit() { throw new AssertionError("This method should not be called."); } + @Override + public void setLastShownList(List>> list) { + throw new AssertionError("This method should not be called."); + } + @Override public void setLastShownList(Map> list) { throw new AssertionError("This method should not be called."); diff --git a/test/java/planmysem/logic/Commands/CommandTestUtil.java b/test/java/planmysem/logic/Commands/CommandTestUtil.java index e8ff6a045..0272c6807 100644 --- a/test/java/planmysem/logic/Commands/CommandTestUtil.java +++ b/test/java/planmysem/logic/Commands/CommandTestUtil.java @@ -3,8 +3,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.LocalDate; -import java.util.Map; -import java.util.TreeMap; +import java.util.ArrayList; +import java.util.List; import javafx.util.Pair; import planmysem.logic.CommandHistory; @@ -104,7 +104,7 @@ public static void assertCommandFailure(Command command, Model actualModel, Comm String expectedMessage) { Planner expectedPlanner = new Planner(actualModel.getPlanner()); actualModel.getDays(); - Map> expectedLastShownList = new TreeMap<>(actualModel.getLastShownList()); + List>> expectedLastShownList = new ArrayList<>(actualModel.getLastShownList()); CommandHistory expectedCommandHistory = new CommandHistory(actualCommandHistory); diff --git a/test/java/planmysem/logic/Commands/EditCommandTest.java b/test/java/planmysem/logic/Commands/EditCommandTest.java index e71be35f6..6250bf0f5 100644 --- a/test/java/planmysem/logic/Commands/EditCommandTest.java +++ b/test/java/planmysem/logic/Commands/EditCommandTest.java @@ -11,7 +11,6 @@ import java.time.LocalDate; import java.time.LocalTime; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -98,11 +97,11 @@ public void setup() throws Exception { model.addSlot(LocalDate.of(2019, 02, 03), slotBuilder.generateSlot(3)); model.addSlot(LocalDate.of(2019, 02, 04), slotBuilder.generateSlot(3)); - Map> list = new HashMap<>(); - list.put(pair1.getKey(), pair1.getValue()); - list.put(pair2.getKey(), pair2.getValue()); - list.put(pair3.getKey(), pair3.getValue()); + Map> list = new TreeMap<>(); list.put(pair4.getKey(), pair4.getValue()); + list.put(pair3.getKey(), pair3.getValue()); + list.put(pair2.getKey(), pair2.getValue()); + list.put(pair1.getKey(), pair1.getValue()); model.setLastShownList(list); expectedModel = new ModelManager();