From f11736cf99775ca7724fd73391fd57744ca53337 Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 15:37:15 +0800 Subject: [PATCH 1/8] Add new predicate --- .../article/ArticleMatchesTagPredicate.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java diff --git a/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java b/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java new file mode 100644 index 00000000000..11254faa55a --- /dev/null +++ b/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java @@ -0,0 +1,32 @@ +package seedu.address.model.article; + +import static java.util.Objects.requireNonNull; + +import java.util.Set; +import java.util.function.Predicate; + +import seedu.address.model.tag.Tag; + +/** + * Checks if article has matching tag + */ +public class ArticleMatchesTagPredicate implements Predicate
{ + private Tag tag; + public ArticleMatchesTagPredicate(Tag tag) { + this.tag = tag; + } + + @Override + public boolean test(Article article) { + Set others = article.getTags(); + boolean predicate = false; + requireNonNull(tag); + for (Tag other : others) { + requireNonNull(other); + if (other.equals(tag)) { + predicate = true; + } + } + return predicate; + } +} From 965e110241ff607dfd6d2d3e102f1b11154b3200 Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 16:42:57 +0800 Subject: [PATCH 2/8] Add filter by tag feature for articles --- .../articlecommands/SetArticleCommand.java | 15 ++++++++++++--- .../logic/parser/SetArticleCommandParser.java | 10 +++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java b/src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java index 858f0a3da92..08a5437b9ad 100644 --- a/src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java +++ b/src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java @@ -12,8 +12,10 @@ import seedu.address.model.Model; import seedu.address.model.article.Article; import seedu.address.model.article.ArticleMatchesStatusPredicate; +import seedu.address.model.article.ArticleMatchesTagPredicate; import seedu.address.model.article.ArticleMatchesTimePeriodPredicate; import seedu.address.model.article.exceptions.InvalidStatusException; +import seedu.address.model.tag.Tag; /** * Use to set filter for Articles @@ -23,14 +25,14 @@ public class SetArticleCommand extends ArticleCommand { public static final String COMMAND_PREFIX = "-a"; - public static final String MESSAGE_SUCCESS = "Filter Updated"; + public static final String MESSAGE_SUCCESS = "filter online"; private Predicate
finalPredicate; /** * Constructs a SetArticleCommand object. * @param status The status to be filtered by. */ - public SetArticleCommand(String status, String start, String end) { + public SetArticleCommand(String status, String tagName, String start, String end) throws ParseException { try { finalPredicate = new ArticleMatchesStatusPredicate(status); } catch (InvalidStatusException e) { @@ -42,7 +44,14 @@ public SetArticleCommand(String status, String start, String end) { Predicate
timePredicate = new ArticleMatchesTimePeriodPredicate(startDate, endDate); finalPredicate = finalPredicate.and(timePredicate); } catch (ParseException e) { - finalPredicate = finalPredicate; + if (!start.equals("") && end.equals("")) { + throw e; + } + } + if (!tagName.trim().equals("")) { + Tag tag = new Tag(tagName); + Predicate
tagPredicate = new ArticleMatchesTagPredicate(tag); + finalPredicate = finalPredicate.and(tagPredicate); } } diff --git a/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java b/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java index 8d46614b4b9..883acaaef6d 100644 --- a/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java @@ -3,11 +3,13 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_END; import static seedu.address.logic.parser.CliSyntax.PREFIX_START; import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; import java.util.stream.Stream; import seedu.address.logic.commands.articlecommands.SetArticleCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.tag.Tag; /** * Parses input arguments and creates a SetArticleCommand object @@ -16,14 +18,16 @@ public class SetArticleCommandParser implements Parser { @Override public SetArticleCommand parse(String userInput) throws ParseException { - ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_STATUS, PREFIX_START, PREFIX_END); - if (!arePrefixesPresent(argMultimap, PREFIX_STATUS, PREFIX_START, PREFIX_END)) { + ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_STATUS, + PREFIX_TAG, PREFIX_START, PREFIX_END); + if (!arePrefixesPresent(argMultimap, PREFIX_STATUS, PREFIX_TAG, PREFIX_START, PREFIX_END)) { throw new ParseException("The set command does not follow the correct format"); } String status = argMultimap.getValue(PREFIX_STATUS).get(); + String tagName = argMultimap.getValue(PREFIX_TAG).get(); String start = argMultimap.getValue(PREFIX_START).get(); String end = argMultimap.getValue(PREFIX_END).get(); - return new SetArticleCommand(status, start, end); + return new SetArticleCommand(status,tagName, start, end); } private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { From 1c194fa27f6f32ecaecd61bffbbe080cdd7c88de Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 16:52:32 +0800 Subject: [PATCH 3/8] Remove redundant import Add whitespace behind comma --- .../seedu/address/logic/parser/SetArticleCommandParser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java b/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java index 883acaaef6d..a002b199a2f 100644 --- a/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java @@ -9,7 +9,6 @@ import seedu.address.logic.commands.articlecommands.SetArticleCommand; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.tag.Tag; /** * Parses input arguments and creates a SetArticleCommand object @@ -27,7 +26,7 @@ public SetArticleCommand parse(String userInput) throws ParseException { String tagName = argMultimap.getValue(PREFIX_TAG).get(); String start = argMultimap.getValue(PREFIX_START).get(); String end = argMultimap.getValue(PREFIX_END).get(); - return new SetArticleCommand(status,tagName, start, end); + return new SetArticleCommand(status, tagName, start, end); } private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { From ac17d7b306c60ce4c4e7526bf602f859ab339c91 Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 19:14:00 +0800 Subject: [PATCH 4/8] Add defensive code Rename set command to Filter to be more intuitive. --- ...ArticleCommand.java => FilterArticleCommand.java} | 8 ++++---- .../address/logic/parser/ArticleBookParser.java | 6 +++--- ...ndParser.java => FilterArticleCommandParser.java} | 12 ++++++------ .../model/article/ArticleMatchesStatusPredicate.java | 4 ++++ .../model/article/ArticleMatchesTagPredicate.java | 1 + 5 files changed, 18 insertions(+), 13 deletions(-) rename src/main/java/seedu/address/logic/commands/articlecommands/{SetArticleCommand.java => FilterArticleCommand.java} (89%) rename src/main/java/seedu/address/logic/parser/{SetArticleCommandParser.java => FilterArticleCommandParser.java} (71%) diff --git a/src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java b/src/main/java/seedu/address/logic/commands/articlecommands/FilterArticleCommand.java similarity index 89% rename from src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java rename to src/main/java/seedu/address/logic/commands/articlecommands/FilterArticleCommand.java index 08a5437b9ad..5009adafb83 100644 --- a/src/main/java/seedu/address/logic/commands/articlecommands/SetArticleCommand.java +++ b/src/main/java/seedu/address/logic/commands/articlecommands/FilterArticleCommand.java @@ -20,8 +20,8 @@ /** * Use to set filter for Articles */ -public class SetArticleCommand extends ArticleCommand { - public static final String COMMAND_WORD = "set"; +public class FilterArticleCommand extends ArticleCommand { + public static final String COMMAND_WORD = "filter"; public static final String COMMAND_PREFIX = "-a"; @@ -29,10 +29,10 @@ public class SetArticleCommand extends ArticleCommand { private Predicate
finalPredicate; /** - * Constructs a SetArticleCommand object. + * Constructs a FilterArticleCommand object. * @param status The status to be filtered by. */ - public SetArticleCommand(String status, String tagName, String start, String end) throws ParseException { + public FilterArticleCommand(String status, String tagName, String start, String end) throws ParseException { try { finalPredicate = new ArticleMatchesStatusPredicate(status); } catch (InvalidStatusException e) { diff --git a/src/main/java/seedu/address/logic/parser/ArticleBookParser.java b/src/main/java/seedu/address/logic/parser/ArticleBookParser.java index 0b49a735b81..bcac2233fd4 100644 --- a/src/main/java/seedu/address/logic/parser/ArticleBookParser.java +++ b/src/main/java/seedu/address/logic/parser/ArticleBookParser.java @@ -13,9 +13,9 @@ import seedu.address.logic.commands.articlecommands.AddArticleCommand; import seedu.address.logic.commands.articlecommands.DeleteArticleCommand; import seedu.address.logic.commands.articlecommands.EditArticleCommand; +import seedu.address.logic.commands.articlecommands.FilterArticleCommand; import seedu.address.logic.commands.articlecommands.FindArticleCommand; import seedu.address.logic.commands.articlecommands.ListArticleCommand; -import seedu.address.logic.commands.articlecommands.SetArticleCommand; import seedu.address.logic.commands.articlecommands.SortArticleCommand; import seedu.address.logic.parser.exceptions.ParseException; @@ -72,8 +72,8 @@ public static Command parseCommand(String userInput) throws ParseException { case SortArticleCommand.COMMAND_WORD: return new SortArticleCommandParser().parse(arguments); - case SetArticleCommand.COMMAND_WORD: - return new SetArticleCommandParser().parse(arguments); + case FilterArticleCommand.COMMAND_WORD: + return new FilterArticleCommandParser().parse(arguments); default: logger.finer("This user input caused a ParseException: " + userInput); diff --git a/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java similarity index 71% rename from src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java rename to src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java index a002b199a2f..f08ada8643d 100644 --- a/src/main/java/seedu/address/logic/parser/SetArticleCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java @@ -7,26 +7,26 @@ import java.util.stream.Stream; -import seedu.address.logic.commands.articlecommands.SetArticleCommand; +import seedu.address.logic.commands.articlecommands.FilterArticleCommand; import seedu.address.logic.parser.exceptions.ParseException; /** - * Parses input arguments and creates a SetArticleCommand object + * Parses input arguments and creates a FilterArticleCommand object */ -public class SetArticleCommandParser implements Parser { +public class FilterArticleCommandParser implements Parser { @Override - public SetArticleCommand parse(String userInput) throws ParseException { + public FilterArticleCommand parse(String userInput) throws ParseException { ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_STATUS, PREFIX_TAG, PREFIX_START, PREFIX_END); if (!arePrefixesPresent(argMultimap, PREFIX_STATUS, PREFIX_TAG, PREFIX_START, PREFIX_END)) { - throw new ParseException("The set command does not follow the correct format"); + throw new ParseException("The filter command does not follow the correct format"); } String status = argMultimap.getValue(PREFIX_STATUS).get(); String tagName = argMultimap.getValue(PREFIX_TAG).get(); String start = argMultimap.getValue(PREFIX_START).get(); String end = argMultimap.getValue(PREFIX_END).get(); - return new SetArticleCommand(status, tagName, start, end); + return new FilterArticleCommand(status, tagName, start, end); } private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { diff --git a/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java b/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java index 0c95ad6652f..3b99dd1c3fe 100644 --- a/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java +++ b/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java @@ -1,5 +1,7 @@ package seedu.address.model.article; +import static java.util.Objects.requireNonNull; + import java.util.function.Predicate; import seedu.address.model.article.exceptions.InvalidStatusException; @@ -29,6 +31,8 @@ public ArticleMatchesStatusPredicate(String s) throws InvalidStatusException { @Override public boolean test(Article article) { + //Check that article is not null. + assert (article instanceof Article); return this.status.equals(article.getStatus()); } diff --git a/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java b/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java index 11254faa55a..0118c9e979b 100644 --- a/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java +++ b/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java @@ -18,6 +18,7 @@ public ArticleMatchesTagPredicate(Tag tag) { @Override public boolean test(Article article) { + requireNonNull(article); Set others = article.getTags(); boolean predicate = false; requireNonNull(tag); From 89a404b419d2e0332496647dc44ae83b2c9b0652 Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 19:16:59 +0800 Subject: [PATCH 5/8] Remove import statement --- .../address/model/article/ArticleMatchesStatusPredicate.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java b/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java index 3b99dd1c3fe..5710217d62c 100644 --- a/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java +++ b/src/main/java/seedu/address/model/article/ArticleMatchesStatusPredicate.java @@ -1,6 +1,5 @@ package seedu.address.model.article; -import static java.util.Objects.requireNonNull; import java.util.function.Predicate; From c5c6ad33e4bb5fe4db10adb72159b1d078c8111b Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 21:09:43 +0800 Subject: [PATCH 6/8] Delete unnecessary files --- docs/DeveloperGuide_BACKUP_487.md | 572 ------------------------------ docs/DeveloperGuide_BASE_487.md | 531 --------------------------- docs/DeveloperGuide_LOCAL_487.md | 556 ----------------------------- docs/DeveloperGuide_REMOTE_487.md | 545 ---------------------------- 4 files changed, 2204 deletions(-) delete mode 100644 docs/DeveloperGuide_BACKUP_487.md delete mode 100644 docs/DeveloperGuide_BASE_487.md delete mode 100644 docs/DeveloperGuide_LOCAL_487.md delete mode 100644 docs/DeveloperGuide_REMOTE_487.md diff --git a/docs/DeveloperGuide_BACKUP_487.md b/docs/DeveloperGuide_BACKUP_487.md deleted file mode 100644 index 5b3163e1a96..00000000000 --- a/docs/DeveloperGuide_BACKUP_487.md +++ /dev/null @@ -1,572 +0,0 @@ - - ---- - layout: default.md - title: "Developer Guide" - pageNav: 3 ---- - -# AB-3 Developer Guide - - - - --------------------------------------------------------------------------------------------------------------------- - -## **Acknowledgements** - -_{ list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well }_ - --------------------------------------------------------------------------------------------------------------------- - -## **Setting up, getting started** - -Refer to the guide [_Setting up and getting started_](SettingUp.md). - --------------------------------------------------------------------------------------------------------------------- - -## **Design** - -### Architecture - - - -The ***Architecture Diagram*** given above explains the high-level design of the App. - -Given below is a quick overview of main components and how they interact with each other. - -**Main components of the architecture** - -**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down. -* At app launch, it initializes the other components in the correct sequence, and connects them up with each other. -* At shut down, it shuts down the other components and invokes cleanup methods where necessary. - -The bulk of the app's work is done by the following four components: - -* [**`UI`**](#ui-component): The UI of the App. -* [**`Logic`**](#logic-component): The command executor. -* [**`Model`**](#model-component): Holds the data of the App in memory. -* [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk. - -[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components. - -**How the architecture components interact with each other** - -The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. - - - -Each of the four main components (also shown in the diagram above), - -* defines its *API* in an `interface` with the same name as the Component. -* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point. - -For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below. - - - -The sections below give more details of each component. - -### UI component - -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) - - - -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. - -The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) - -The `UI` component, - -* executes user commands using the `Logic` component. -* listens for changes to `Model` data so that the UI can be updated with the modified data. -* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. - -### Logic component - -**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: - - - -The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example. - - - - - -**Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram. - - -How the `Logic` component works: - -1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command. -1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`. -1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
- Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve. -1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. - -Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command: - - - -How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. If the command deals with Articles then the `AddressBookParser` will pass it to the `ArticleBookParser` which will then handle to command similarly to the `AddressBookParser`. -* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. - -### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) - - - - -The `Model` component, - -* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. -* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) - - - -**Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
- - - -
- - -### Storage component - -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) - - - -The `Storage` component, -* can save address book data, article book data and user preference data in JSON format, and read them back into corresponding objects. -* inherits from `AddressBookStorage`, `ArticleBookStorage` and `UserPrefStorage`, which means it can be treated as any one of these (if only the functionality of only one is needed). -* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) - -### Common classes - -Classes used by multiple components are in the `seedu.addressbook.commons` package. - --------------------------------------------------------------------------------------------------------------------- - -## **Implementation** - -This section describes some noteworthy details on how certain features are implemented. - -### \[Implementing\] Filter feature - - - -The filter mechanism is facilitated by `filter` interface. The ArticleFilter and PersonFilter classes will inherit from it. -The filters will store `Predicate<>` objects that will determine which Persons or articles will be shown to the user. -`ModelManager` will contain a filter, which it will use to generate `FilteredLists` - -Given below is an example usage scenario: - -Step 1. The user launches the application. The `ModelManager` will be initialized, along with the Filter objects it contains. `finalPredicate` will be set to display all articles for now. - -Step 2. The user executes `set -a S/DRAFT ST/ EN/` to look for articles he is currently working on. The set command gets the `ArticleFilter` object using `getFilter()`. Than it updates the filter object by calling the `updateFilter()` method, changing the `finalPredicate`. - - - -Step 3. Now that the filter has been updated. The user now looks through Press Planner to search for the article. He decides to search by title to make it faster. He executes `find -a AI`. Beyond matches with the name, Press Planner is still filtering to show only DRAFTs, allowing the user to search a smaller set. - -Step 4. The user has found his article and wishes to remove the filter. He does this by executing `set -a S/ ST/ EN/`. With no instructions, the predicate allows all articles to pass through the filter. - -Note: If start date is later than the end date, Press Planner will refuse to execute the command, double check the dates to avoid this scenario. - -Note: Filters are **NOT** stored by the program. If you close the app, your filters will be reset. - -### \[Proposed\] 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: - -* `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. - - - -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 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`. - - - - - -**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. - - - - - - -**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. - - - -The following sequence diagram shows how an undo operation goes through the `Logic` component: - - - - - -**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. - - - -Similarly, how an undo operation goes through the `Model` component is shown below: - - - -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 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. - - - -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. - - - -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}_ - -<<<<<<< HEAD -======= -### \[Proposed\] Lookup Article - -#### Proposed Implementation - -The proposed lookup feature is enabled by altering `Article` such that whenever one is created, it stores a list of `Person` objects that are the Authors or Sources involved in the article. The `LookUpCommand` feature will then retrieve this list and display it to the user, enabling the user to see Persons involved in the article. - -#### Design considerations: - -* Make sure Edits and Deletes of Persons and Articles are handled correctly. -* Consider including a UI alternative to access the list: Pressing a button in the Article's display will show the list of Persons involved. - ->>>>>>> master - -### \[Proposed\] Data archiving - -_{Explain here how the data archiving feature will be implemented}_ - - --------------------------------------------------------------------------------------------------------------------- - -## **Documentation, logging, testing, configuration, dev-ops** - -* [Documentation guide](Documentation.md) -* [Testing guide](Testing.md) -* [Logging guide](Logging.md) -* [Configuration guide](Configuration.md) -* [DevOps guide](DevOps.md) - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Requirements** - -### Product scope - -**Target user profile**: - -* freelance journalists -* has a need to manage a significant number of contacts for different facets of business -* prefer using text-based commands than multi-step GUI -* can type fast -* value speed and efficiency - -**Value proposition**: An app for freelance journalists that can streamline their workflow by organizing sources, tracking outlets interested in their stories, and managing collaborations with peers/editors. With features like tagging and grouping contacts, it facilitates efficient research, ensuring reporters can quickly reach out and report on breaking stories. - - - -### User stories - -Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` - -| Priority | As a …​ | I want to …​ | So that I can…​ | -|----------|--------------------------------------------|------------------------------|------------------------------------------------------------------------| -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | user | add a new person | | -| `* * *` | user | delete a person | remove entries that I no longer need | -| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list | -| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident | -| `*` | user with many persons in the address book | sort persons by name | locate a person easily | - -*{More to be added}* - -### Use cases - -(For all use cases below, the **System** is the `PressPlanner` and the **Actor** is the `user`, unless specified otherwise) - -**Use case: Delete a person** - -**MSS** - -1. User requests to list persons. -1. AddressBook shows a list of persons. -1. User requests to delete a specific person in the list. -1. AddressBook deletes the person. - - Use case ends. - -**Extensions** - -* 2a. The list is empty. - - Use case ends. - - -* 3a. The given index is invalid. - - * 3a1. AddressBook shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC01 - Add an article** - -**MSS** -1. User requests to add article. -1. PressPlanner adds article. -1. PressPlanner displays success message to User. - - Use case ends. - -**Extensions** - -* 1a. Command was invalid. - * 1a1. PressPlanner shows an error message. - - Use case ends. - - - -**Use case: UC02 - List all articles** - -**MSS** -1. User requests to list articles. -1. PressPlanner lists out all articles. - - Use case ends. - -**Extensions** - -* 1a. The list is empty. - * 1a1. PressPlanner returns an error message. - - Use case ends. - - - -**Use case: UC03 - Edit an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to edit a specific article in the list - by providing at least one change to an attribute of the article. -1. PressPlanner updates the article with the changes requested. -1. PressPlanner shows the updated article to user. - - Use case ends. - -**Extensions** - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. No changes to an attribute of the article is specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC04 - Delete an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to delete a specific article in the list. -1. PressPlanner deletes the article. -1. PressPlanner shows delete success message to user. - - Use case ends. - -**Extensions** - -* 2a. User requests to find articles with given keywords. - - * 2a1. PressPlanner displays a filtered list of articles found. - - Use case resumes at step 3. - - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC05 - Find articles** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to find articles with given keywords. -1. PressPlanner displays a filtered list of articles found, - each containing at least one of the given keywords. - - Use case ends. - -**Extensions** - -* 3a. No keywords are specified. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. Only invalid keywords are specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3c. No articles are found with the given keywords. - - * 3c1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -### Non-Functional Requirements - -1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -1. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -1. Should be able to hold up to 1000 articles without a noticeable sluggishness in performance for typical usage. -1. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. - - - -### Glossary - -* **Mainstream OS**: Windows, Linux, Unix, MacOS -* **Private contact detail**: A contact detail that is not meant to be shared with others -* **Story**: A story written by interviewing the person -* **Tag**: Additional information about the person on level of how helpful the person was for a journal. - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Instructions for manual testing** - -Given below are instructions to test the app manually. - - - -**Note:** These instructions only provide a starting point for testers to work on; -testers are expected to do more *exploratory* testing. - - - -### Launch and shutdown - -1. Initial launch - - 1. Download the jar file and copy into an empty folder - - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. - -1. Saving window preferences - - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. - - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. - -1. _{ more test cases …​ }_ - -### Deleting a person - -1. Deleting a person while all persons are being shown - - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. - - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. - - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. - - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. - -1. _{ more test cases …​ }_ - -### Saving data - -1. Dealing with missing/corrupted data files - - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ - -1. _{ more test cases …​ }_ diff --git a/docs/DeveloperGuide_BASE_487.md b/docs/DeveloperGuide_BASE_487.md deleted file mode 100644 index 5832ca074b2..00000000000 --- a/docs/DeveloperGuide_BASE_487.md +++ /dev/null @@ -1,531 +0,0 @@ ---- - layout: default.md - title: "Developer Guide" - pageNav: 3 ---- - -# AB-3 Developer Guide - - - - --------------------------------------------------------------------------------------------------------------------- - -## **Acknowledgements** - -_{ list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well }_ - --------------------------------------------------------------------------------------------------------------------- - -## **Setting up, getting started** - -Refer to the guide [_Setting up and getting started_](SettingUp.md). - --------------------------------------------------------------------------------------------------------------------- - -## **Design** - -### Architecture - - - -The ***Architecture Diagram*** given above explains the high-level design of the App. - -Given below is a quick overview of main components and how they interact with each other. - -**Main components of the architecture** - -**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down. -* At app launch, it initializes the other components in the correct sequence, and connects them up with each other. -* At shut down, it shuts down the other components and invokes cleanup methods where necessary. - -The bulk of the app's work is done by the following four components: - -* [**`UI`**](#ui-component): The UI of the App. -* [**`Logic`**](#logic-component): The command executor. -* [**`Model`**](#model-component): Holds the data of the App in memory. -* [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk. - -[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components. - -**How the architecture components interact with each other** - -The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. - - - -Each of the four main components (also shown in the diagram above), - -* defines its *API* in an `interface` with the same name as the Component. -* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point. - -For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below. - - - -The sections below give more details of each component. - -### UI component - -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) - - - -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. - -The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) - -The `UI` component, - -* executes user commands using the `Logic` component. -* listens for changes to `Model` data so that the UI can be updated with the modified data. -* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. - -### Logic component - -**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: - - - -The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example. - - - - - -**Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram. - - -How the `Logic` component works: - -1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command. -1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`. -1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
- Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve. -1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. - -Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command: - - - -How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. -* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. - -### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) - - - - -The `Model` component, - -* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. -* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) - - - -**Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
- - - -
- - -### Storage component - -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) - - - -The `Storage` component, -* can save both address book data and user preference data in JSON format, and read them back into corresponding objects. -* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). -* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) - -### Common classes - -Classes used by multiple components are in the `seedu.addressbook.commons` package. - --------------------------------------------------------------------------------------------------------------------- - -## **Implementation** - -This section describes some noteworthy details on how certain features are implemented. - -### \[Proposed\] 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: - -* `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. - - - -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 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`. - - - - - -**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. - - - - - - -**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. - - - -The following sequence diagram shows how an undo operation goes through the `Logic` component: - - - - - -**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. - - - -Similarly, how an undo operation goes through the `Model` component is shown below: - - - -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 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. - - - -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. - - - -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 - -_{Explain here how the data archiving feature will be implemented}_ - - --------------------------------------------------------------------------------------------------------------------- - -## **Documentation, logging, testing, configuration, dev-ops** - -* [Documentation guide](Documentation.md) -* [Testing guide](Testing.md) -* [Logging guide](Logging.md) -* [Configuration guide](Configuration.md) -* [DevOps guide](DevOps.md) - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Requirements** - -### Product scope - -**Target user profile**: - -* freelance journalists -* has a need to manage a significant number of contacts for different facets of business -* prefer using text-based commands than multi-step GUI -* can type fast -* value speed and efficiency - -**Value proposition**: An app for freelance journalists that can streamline their workflow by organizing sources, tracking outlets interested in their stories, and managing collaborations with peers/editors. With features like tagging and grouping contacts, it facilitates efficient research, ensuring reporters can quickly reach out and report on breaking stories. - - - -### User stories - -Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` - -| Priority | As a …​ | I want to …​ | So that I can…​ | -|----------|--------------------------------------------|------------------------------|------------------------------------------------------------------------| -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | user | add a new person | | -| `* * *` | user | delete a person | remove entries that I no longer need | -| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list | -| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident | -| `*` | user with many persons in the address book | sort persons by name | locate a person easily | - -*{More to be added}* - -### Use cases - -(For all use cases below, the **System** is the `PressPlanner` and the **Actor** is the `user`, unless specified otherwise) - -**Use case: Delete a person** - -**MSS** - -1. User requests to list persons. -1. AddressBook shows a list of persons. -1. User requests to delete a specific person in the list. -1. AddressBook deletes the person. - - Use case ends. - -**Extensions** - -* 2a. The list is empty. - - Use case ends. - - -* 3a. The given index is invalid. - - * 3a1. AddressBook shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC01 - Add an article** - -**MSS** -1. User requests to add article. -1. PressPlanner adds article. -1. PressPlanner displays success message to User. - - Use case ends. - -**Extensions** - -* 1a. Command was invalid. - * 1a1. PressPlanner shows an error message. - - Use case ends. - - - -**Use case: UC02 - List all articles** - -**MSS** -1. User requests to list articles. -1. PressPlanner lists out all articles. - - Use case ends. - -**Extensions** - -* 1a. The list is empty. - * 1a1. PressPlanner returns an error message. - - Use case ends. - - - -**Use case: UC03 - Edit an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to edit a specific article in the list - by providing at least one change to an attribute of the article. -1. PressPlanner updates the article with the changes requested. -1. PressPlanner shows the updated article to user. - - Use case ends. - -**Extensions** - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. No changes to an attribute of the article is specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC04 - Delete an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to delete a specific article in the list. -1. PressPlanner deletes the article. -1. PressPlanner shows delete success message to user. - - Use case ends. - -**Extensions** - -* 2a. User requests to find articles with given keywords. - - * 2a1. PressPlanner displays a filtered list of articles found. - - Use case resumes at step 3. - - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC05 - Find articles** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to find articles with given keywords. -1. PressPlanner displays a filtered list of articles found, - each containing at least one of the given keywords. - - Use case ends. - -**Extensions** - -* 3a. No keywords are specified. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. Only invalid keywords are specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3c. No articles are found with the given keywords. - - * 3c1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -### Non-Functional Requirements - -1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -1. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -1. Should be able to hold up to 1000 articles without a noticeable sluggishness in performance for typical usage. -1. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. - - - -### Glossary - -* **Mainstream OS**: Windows, Linux, Unix, MacOS -* **Private contact detail**: A contact detail that is not meant to be shared with others -* **Story**: A story written by interviewing the person -* **Tag**: Additional information about the person on level of how helpful the person was for a journal. - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Instructions for manual testing** - -Given below are instructions to test the app manually. - - - -**Note:** These instructions only provide a starting point for testers to work on; -testers are expected to do more *exploratory* testing. - - - -### Launch and shutdown - -1. Initial launch - - 1. Download the jar file and copy into an empty folder - - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. - -1. Saving window preferences - - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. - - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. - -1. _{ more test cases …​ }_ - -### Deleting a person - -1. Deleting a person while all persons are being shown - - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. - - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. - - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. - - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. - -1. _{ more test cases …​ }_ - -### Saving data - -1. Dealing with missing/corrupted data files - - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ - -1. _{ more test cases …​ }_ diff --git a/docs/DeveloperGuide_LOCAL_487.md b/docs/DeveloperGuide_LOCAL_487.md deleted file mode 100644 index bbaefc12632..00000000000 --- a/docs/DeveloperGuide_LOCAL_487.md +++ /dev/null @@ -1,556 +0,0 @@ ---- - layout: default.md - title: "Developer Guide" - pageNav: 3 ---- - -# AB-3 Developer Guide - - - - --------------------------------------------------------------------------------------------------------------------- - -## **Acknowledgements** - -_{ list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well }_ - --------------------------------------------------------------------------------------------------------------------- - -## **Setting up, getting started** - -Refer to the guide [_Setting up and getting started_](SettingUp.md). - --------------------------------------------------------------------------------------------------------------------- - -## **Design** - -### Architecture - - - -The ***Architecture Diagram*** given above explains the high-level design of the App. - -Given below is a quick overview of main components and how they interact with each other. - -**Main components of the architecture** - -**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down. -* At app launch, it initializes the other components in the correct sequence, and connects them up with each other. -* At shut down, it shuts down the other components and invokes cleanup methods where necessary. - -The bulk of the app's work is done by the following four components: - -* [**`UI`**](#ui-component): The UI of the App. -* [**`Logic`**](#logic-component): The command executor. -* [**`Model`**](#model-component): Holds the data of the App in memory. -* [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk. - -[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components. - -**How the architecture components interact with each other** - -The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. - - - -Each of the four main components (also shown in the diagram above), - -* defines its *API* in an `interface` with the same name as the Component. -* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point. - -For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below. - - - -The sections below give more details of each component. - -### UI component - -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) - - - -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. - -The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) - -The `UI` component, - -* executes user commands using the `Logic` component. -* listens for changes to `Model` data so that the UI can be updated with the modified data. -* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. - -### Logic component - -**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: - - - -The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example. - - - - - -**Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram. - - -How the `Logic` component works: - -1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command. -1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`. -1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
- Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve. -1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. - -Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command: - - - -How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. -* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. - -### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) - - - - -The `Model` component, - -* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. -* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) - - - -**Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
- - - -
- - -### Storage component - -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) - - - -The `Storage` component, -* can save address book data, article book data and user preference data in JSON format, and read them back into corresponding objects. -* inherits from `AddressBookStorage`, `ArticleBookStorage` and `UserPrefStorage`, which means it can be treated as any one of these (if only the functionality of only one is needed). -* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) - -### Common classes - -Classes used by multiple components are in the `seedu.addressbook.commons` package. - --------------------------------------------------------------------------------------------------------------------- - -## **Implementation** - -This section describes some noteworthy details on how certain features are implemented. - -### \[Implementing\] Filter feature - - - -The filter mechanism is facilitated by `filter` interface. The ArticleFilter and PersonFilter classes will inherit from it. -The filters will store `Predicate<>` objects that will determine which Persons or articles will be shown to the user. -`ModelManager` will contain a filter, which it will use to generate `FilteredLists` - -Given below is an example usage scenario: - -Step 1. The user launches the application. The `ModelManager` will be initialized, along with the Filter objects it contains. `finalPredicate` will be set to display all articles for now. - -Step 2. The user executes `set -a S/DRAFT ST/ EN/` to look for articles he is currently working on. The set command gets the `ArticleFilter` object using `getFilter()`. Than it updates the filter object by calling the `updateFilter()` method, changing the `finalPredicate`. - - - -Step 3. Now that the filter has been updated. The user now looks through Press Planner to search for the article. He decides to search by title to make it faster. He executes `find -a AI`. Beyond matches with the name, Press Planner is still filtering to show only DRAFTs, allowing the user to search a smaller set. - -Step 4. The user has found his article and wishes to remove the filter. He does this by executing `set -a S/ ST/ EN/`. With no instructions, the predicate allows all articles to pass through the filter. - -Note: If start date is later than the end date, Press Planner will refuse to execute the command, double check the dates to avoid this scenario. - -Note: Filters are **NOT** stored by the program. If you close the app, your filters will be reset. - -### \[Proposed\] 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: - -* `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. - - - -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 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`. - - - - - -**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. - - - - - - -**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. - - - -The following sequence diagram shows how an undo operation goes through the `Logic` component: - - - - - -**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. - - - -Similarly, how an undo operation goes through the `Model` component is shown below: - - - -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 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. - - - -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. - - - -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 - -_{Explain here how the data archiving feature will be implemented}_ - - --------------------------------------------------------------------------------------------------------------------- - -## **Documentation, logging, testing, configuration, dev-ops** - -* [Documentation guide](Documentation.md) -* [Testing guide](Testing.md) -* [Logging guide](Logging.md) -* [Configuration guide](Configuration.md) -* [DevOps guide](DevOps.md) - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Requirements** - -### Product scope - -**Target user profile**: - -* freelance journalists -* has a need to manage a significant number of contacts for different facets of business -* prefer using text-based commands than multi-step GUI -* can type fast -* value speed and efficiency - -**Value proposition**: An app for freelance journalists that can streamline their workflow by organizing sources, tracking outlets interested in their stories, and managing collaborations with peers/editors. With features like tagging and grouping contacts, it facilitates efficient research, ensuring reporters can quickly reach out and report on breaking stories. - - - -### User stories - -Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` - -| Priority | As a …​ | I want to …​ | So that I can…​ | -|----------|--------------------------------------------|------------------------------|------------------------------------------------------------------------| -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | user | add a new person | | -| `* * *` | user | delete a person | remove entries that I no longer need | -| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list | -| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident | -| `*` | user with many persons in the address book | sort persons by name | locate a person easily | - -*{More to be added}* - -### Use cases - -(For all use cases below, the **System** is the `PressPlanner` and the **Actor** is the `user`, unless specified otherwise) - -**Use case: Delete a person** - -**MSS** - -1. User requests to list persons. -1. AddressBook shows a list of persons. -1. User requests to delete a specific person in the list. -1. AddressBook deletes the person. - - Use case ends. - -**Extensions** - -* 2a. The list is empty. - - Use case ends. - - -* 3a. The given index is invalid. - - * 3a1. AddressBook shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC01 - Add an article** - -**MSS** -1. User requests to add article. -1. PressPlanner adds article. -1. PressPlanner displays success message to User. - - Use case ends. - -**Extensions** - -* 1a. Command was invalid. - * 1a1. PressPlanner shows an error message. - - Use case ends. - - - -**Use case: UC02 - List all articles** - -**MSS** -1. User requests to list articles. -1. PressPlanner lists out all articles. - - Use case ends. - -**Extensions** - -* 1a. The list is empty. - * 1a1. PressPlanner returns an error message. - - Use case ends. - - - -**Use case: UC03 - Edit an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to edit a specific article in the list - by providing at least one change to an attribute of the article. -1. PressPlanner updates the article with the changes requested. -1. PressPlanner shows the updated article to user. - - Use case ends. - -**Extensions** - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. No changes to an attribute of the article is specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC04 - Delete an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to delete a specific article in the list. -1. PressPlanner deletes the article. -1. PressPlanner shows delete success message to user. - - Use case ends. - -**Extensions** - -* 2a. User requests to find articles with given keywords. - - * 2a1. PressPlanner displays a filtered list of articles found. - - Use case resumes at step 3. - - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC05 - Find articles** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to find articles with given keywords. -1. PressPlanner displays a filtered list of articles found, - each containing at least one of the given keywords. - - Use case ends. - -**Extensions** - -* 3a. No keywords are specified. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. Only invalid keywords are specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3c. No articles are found with the given keywords. - - * 3c1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -### Non-Functional Requirements - -1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -1. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -1. Should be able to hold up to 1000 articles without a noticeable sluggishness in performance for typical usage. -1. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. - - - -### Glossary - -* **Mainstream OS**: Windows, Linux, Unix, MacOS -* **Private contact detail**: A contact detail that is not meant to be shared with others -* **Story**: A story written by interviewing the person -* **Tag**: Additional information about the person on level of how helpful the person was for a journal. - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Instructions for manual testing** - -Given below are instructions to test the app manually. - - - -**Note:** These instructions only provide a starting point for testers to work on; -testers are expected to do more *exploratory* testing. - - - -### Launch and shutdown - -1. Initial launch - - 1. Download the jar file and copy into an empty folder - - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. - -1. Saving window preferences - - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. - - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. - -1. _{ more test cases …​ }_ - -### Deleting a person - -1. Deleting a person while all persons are being shown - - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. - - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. - - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. - - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. - -1. _{ more test cases …​ }_ - -### Saving data - -1. Dealing with missing/corrupted data files - - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ - -1. _{ more test cases …​ }_ diff --git a/docs/DeveloperGuide_REMOTE_487.md b/docs/DeveloperGuide_REMOTE_487.md deleted file mode 100644 index 3931afd7592..00000000000 --- a/docs/DeveloperGuide_REMOTE_487.md +++ /dev/null @@ -1,545 +0,0 @@ - - ---- - layout: default.md - title: "Developer Guide" - pageNav: 3 ---- - -# AB-3 Developer Guide - - - - --------------------------------------------------------------------------------------------------------------------- - -## **Acknowledgements** - -_{ list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well }_ - --------------------------------------------------------------------------------------------------------------------- - -## **Setting up, getting started** - -Refer to the guide [_Setting up and getting started_](SettingUp.md). - --------------------------------------------------------------------------------------------------------------------- - -## **Design** - -### Architecture - - - -The ***Architecture Diagram*** given above explains the high-level design of the App. - -Given below is a quick overview of main components and how they interact with each other. - -**Main components of the architecture** - -**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down. -* At app launch, it initializes the other components in the correct sequence, and connects them up with each other. -* At shut down, it shuts down the other components and invokes cleanup methods where necessary. - -The bulk of the app's work is done by the following four components: - -* [**`UI`**](#ui-component): The UI of the App. -* [**`Logic`**](#logic-component): The command executor. -* [**`Model`**](#model-component): Holds the data of the App in memory. -* [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk. - -[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components. - -**How the architecture components interact with each other** - -The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. - - - -Each of the four main components (also shown in the diagram above), - -* defines its *API* in an `interface` with the same name as the Component. -* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point. - -For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below. - - - -The sections below give more details of each component. - -### UI component - -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) - - - -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. - -The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) - -The `UI` component, - -* executes user commands using the `Logic` component. -* listens for changes to `Model` data so that the UI can be updated with the modified data. -* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. - -### Logic component - -**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: - - - -The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example. - - - - - -**Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram. - - -How the `Logic` component works: - -1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command. -1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`. -1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
- Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve. -1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. - -Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command: - - - -How the parsing works: -* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. If the command deals with Articles then the `AddressBookParser` will pass it to the `ArticleBookParser` which will then handle to command similarly to the `AddressBookParser`. -* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. - -### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) - - - - -The `Model` component, - -* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. -* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) - - - -**Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
- - - -
- - -### Storage component - -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) - - - -The `Storage` component, -* can save both address book data and user preference data in JSON format, and read them back into corresponding objects. -* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). -* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) - -### Common classes - -Classes used by multiple components are in the `seedu.addressbook.commons` package. - --------------------------------------------------------------------------------------------------------------------- - -## **Implementation** - -This section describes some noteworthy details on how certain features are implemented. - -### \[Proposed\] 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: - -* `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. - - - -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 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`. - - - - - -**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. - - - - - - -**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. - - - -The following sequence diagram shows how an undo operation goes through the `Logic` component: - - - - - -**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. - - - -Similarly, how an undo operation goes through the `Model` component is shown below: - - - -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 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. - - - -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. - - - -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\] Lookup Article - -#### Proposed Implementation - -The proposed lookup feature is enabled by altering `Article` such that whenever one is created, it stores a list of `Person` objects that are the Authors or Sources involved in the article. The `LookUpCommand` feature will then retrieve this list and display it to the user, enabling the user to see Persons involved in the article. - -#### Design considerations: - -* Make sure Edits and Deletes of Persons and Articles are handled correctly. -* Consider including a UI alternative to access the list: Pressing a button in the Article's display will show the list of Persons involved. - - -### \[Proposed\] Data archiving - -_{Explain here how the data archiving feature will be implemented}_ - - --------------------------------------------------------------------------------------------------------------------- - -## **Documentation, logging, testing, configuration, dev-ops** - -* [Documentation guide](Documentation.md) -* [Testing guide](Testing.md) -* [Logging guide](Logging.md) -* [Configuration guide](Configuration.md) -* [DevOps guide](DevOps.md) - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Requirements** - -### Product scope - -**Target user profile**: - -* freelance journalists -* has a need to manage a significant number of contacts for different facets of business -* prefer using text-based commands than multi-step GUI -* can type fast -* value speed and efficiency - -**Value proposition**: An app for freelance journalists that can streamline their workflow by organizing sources, tracking outlets interested in their stories, and managing collaborations with peers/editors. With features like tagging and grouping contacts, it facilitates efficient research, ensuring reporters can quickly reach out and report on breaking stories. - - - -### User stories - -Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` - -| Priority | As a …​ | I want to …​ | So that I can…​ | -|----------|--------------------------------------------|------------------------------|------------------------------------------------------------------------| -| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App | -| `* * *` | user | add a new person | | -| `* * *` | user | delete a person | remove entries that I no longer need | -| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list | -| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident | -| `*` | user with many persons in the address book | sort persons by name | locate a person easily | - -*{More to be added}* - -### Use cases - -(For all use cases below, the **System** is the `PressPlanner` and the **Actor** is the `user`, unless specified otherwise) - -**Use case: Delete a person** - -**MSS** - -1. User requests to list persons. -1. AddressBook shows a list of persons. -1. User requests to delete a specific person in the list. -1. AddressBook deletes the person. - - Use case ends. - -**Extensions** - -* 2a. The list is empty. - - Use case ends. - - -* 3a. The given index is invalid. - - * 3a1. AddressBook shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC01 - Add an article** - -**MSS** -1. User requests to add article. -1. PressPlanner adds article. -1. PressPlanner displays success message to User. - - Use case ends. - -**Extensions** - -* 1a. Command was invalid. - * 1a1. PressPlanner shows an error message. - - Use case ends. - - - -**Use case: UC02 - List all articles** - -**MSS** -1. User requests to list articles. -1. PressPlanner lists out all articles. - - Use case ends. - -**Extensions** - -* 1a. The list is empty. - * 1a1. PressPlanner returns an error message. - - Use case ends. - - - -**Use case: UC03 - Edit an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to edit a specific article in the list - by providing at least one change to an attribute of the article. -1. PressPlanner updates the article with the changes requested. -1. PressPlanner shows the updated article to user. - - Use case ends. - -**Extensions** - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. No changes to an attribute of the article is specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC04 - Delete an article** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to delete a specific article in the list. -1. PressPlanner deletes the article. -1. PressPlanner shows delete success message to user. - - Use case ends. - -**Extensions** - -* 2a. User requests to find articles with given keywords. - - * 2a1. PressPlanner displays a filtered list of articles found. - - Use case resumes at step 3. - - -* 3a. The given index is invalid. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -**Use case: UC05 - Find articles** - -**MSS** - -1. User requests to list articles. -1. PressPlanner lists out all articles. -1. User requests to find articles with given keywords. -1. PressPlanner displays a filtered list of articles found, - each containing at least one of the given keywords. - - Use case ends. - -**Extensions** - -* 3a. No keywords are specified. - - * 3a1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3b. Only invalid keywords are specified. - - * 3b1. PressPlanner shows an error message. - - Use case resumes at step 2. - - -* 3c. No articles are found with the given keywords. - - * 3c1. PressPlanner shows an error message. - - Use case resumes at step 2. - - - -### Non-Functional Requirements - -1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed. -1. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage. -1. Should be able to hold up to 1000 articles without a noticeable sluggishness in performance for typical usage. -1. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. - - - -### Glossary - -* **Mainstream OS**: Windows, Linux, Unix, MacOS -* **Private contact detail**: A contact detail that is not meant to be shared with others -* **Story**: A story written by interviewing the person -* **Tag**: Additional information about the person on level of how helpful the person was for a journal. - --------------------------------------------------------------------------------------------------------------------- - -## **Appendix: Instructions for manual testing** - -Given below are instructions to test the app manually. - - - -**Note:** These instructions only provide a starting point for testers to work on; -testers are expected to do more *exploratory* testing. - - - -### Launch and shutdown - -1. Initial launch - - 1. Download the jar file and copy into an empty folder - - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. - -1. Saving window preferences - - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. - - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. - -1. _{ more test cases …​ }_ - -### Deleting a person - -1. Deleting a person while all persons are being shown - - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. - - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. - - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. - - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. - -1. _{ more test cases …​ }_ - -### Saving data - -1. Dealing with missing/corrupted data files - - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ - -1. _{ more test cases …​ }_ From 02ba69c6d906da9e65a62c8f8aed1c90947de82d Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 21:15:26 +0800 Subject: [PATCH 7/8] Replace prefix tag with article tag prefix --- .../address/logic/parser/FilterArticleCommandParser.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java index f08ada8643d..1dce899d513 100644 --- a/src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FilterArticleCommandParser.java @@ -1,9 +1,9 @@ package seedu.address.logic.parser; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ARTICLETAG; import static seedu.address.logic.parser.CliSyntax.PREFIX_END; import static seedu.address.logic.parser.CliSyntax.PREFIX_START; import static seedu.address.logic.parser.CliSyntax.PREFIX_STATUS; -import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; import java.util.stream.Stream; @@ -18,12 +18,12 @@ public class FilterArticleCommandParser implements Parser @Override public FilterArticleCommand parse(String userInput) throws ParseException { ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(userInput, PREFIX_STATUS, - PREFIX_TAG, PREFIX_START, PREFIX_END); - if (!arePrefixesPresent(argMultimap, PREFIX_STATUS, PREFIX_TAG, PREFIX_START, PREFIX_END)) { + PREFIX_ARTICLETAG, PREFIX_START, PREFIX_END); + if (!arePrefixesPresent(argMultimap, PREFIX_STATUS, PREFIX_ARTICLETAG, PREFIX_START, PREFIX_END)) { throw new ParseException("The filter command does not follow the correct format"); } String status = argMultimap.getValue(PREFIX_STATUS).get(); - String tagName = argMultimap.getValue(PREFIX_TAG).get(); + String tagName = argMultimap.getValue(PREFIX_ARTICLETAG).get(); String start = argMultimap.getValue(PREFIX_START).get(); String end = argMultimap.getValue(PREFIX_END).get(); return new FilterArticleCommand(status, tagName, start, end); From f434f936c9066a542bf614feaeede1c4615a4510 Mon Sep 17 00:00:00 2001 From: Ko-Khan Date: Sat, 30 Mar 2024 21:20:07 +0800 Subject: [PATCH 8/8] Change boolean variable name --- .../address/model/article/ArticleMatchesTagPredicate.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java b/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java index 0118c9e979b..0cdf75e0e37 100644 --- a/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java +++ b/src/main/java/seedu/address/model/article/ArticleMatchesTagPredicate.java @@ -20,14 +20,14 @@ public ArticleMatchesTagPredicate(Tag tag) { public boolean test(Article article) { requireNonNull(article); Set others = article.getTags(); - boolean predicate = false; + boolean isMatch = false; requireNonNull(tag); for (Tag other : others) { requireNonNull(other); if (other.equals(tag)) { - predicate = true; + isMatch = true; } } - return predicate; + return isMatch; } }