Skip to content

Commit

Permalink
Merge branch 'master' into branch-handle-grades-error
Browse files Browse the repository at this point in the history
  • Loading branch information
tohjh authored Oct 16, 2024
2 parents b1799f3 + c98104b commit a8c2456
Show file tree
Hide file tree
Showing 17 changed files with 554 additions and 20 deletions.
36 changes: 29 additions & 7 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,19 +135,40 @@ Examples:
* `find alex david` returns `Alex Yeoh`, `David Li`<br>
![result for 'find alex david'](images/findAlexDavidResult.png)


### Locating persons by tag: `filter`

Finds persons whose names contain any of the given keywords.

Format: `filter t/TAG [t/MORE_TAG]...`

* The search is case-sensitive. e.g `friends` will not match `Friends`
* At least one tag must be provided.
* The order of the keywords does not matter. e.g. `t/friends t/family` will match `t/family t/friends`
* Only the tags is searched.
* Only full tag name will be matched e.g. `friend` will not match `friends`
* Persons matching at least one keyword will be returned (i.e. `OR` search).
e.g. `t/friends t/family` will return any contact tagged with `friend` or `family`.

Examples:
* `filter t/friend t/family` returns any contact tagged with `friend` or `family`<br>
![result for 'filter t/friend t/family'](images/findAlexDavidResult.png)


### Deleting a person : `delete`

Deletes the specified person from the address book.

Format: `delete INDEX`
Format: `delete n/NAME`

* Deletes the person at the specified `INDEX`.
* The index refers to the index number shown in the displayed person list.
* The index **must be a positive integer** 1, 2, 3, …​
* Deletes the person with the specified name.
* The name refers to the full name of the person shown in the displayed person list.
* If a person matches the name but is not shown in the list, it will not be deleted.

Examples:
* `list` followed by `delete 2` deletes the 2nd person in the address book.
* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
* `list` followed by `delete n/Betsy` deletes the person with the name `Betsy`.
* `find Betsy` followed by `delete Alex` will not delete the person named `Alex`.
* `delete n/Betsy` deletes the person named `Betsy` if it is shown on the filtered list.

### Clearing all entries : `clear`

Expand Down Expand Up @@ -202,8 +223,9 @@ Action | Format, Examples
-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------
**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS telegram/TELEGRAM [t/TAG]…​ github/GITHUB` <br> e.g., `add n/James Ho p/22224444 e/[email protected] a/123, Clementi Rd, 1234665 telegram/@James t/friend t/colleague github/james-cool`
**Clear** | `clear`
**Delete** | `delete INDEX`<br> e.g., `delete 3`
**Delete** | `delete n/NAME`<br> e.g., `delete n/James`
**Edit** | `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [telegram/TELEGRAM] [t/TAG]…​ [github/GITHUB]`<br> e.g.,`edit 2 n/James Lee e/[email protected]`
**Find** | `find KEYWORD [MORE_KEYWORDS]`<br> e.g., `find James Jake`
**Filter** | `filter t/[TAG] t/[MORE_TAG]…​`<br> e.g., `filter t/friends t/family`
**List** | `list`
**Help** | `help`
3 changes: 2 additions & 1 deletion src/main/java/seedu/address/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
logger.warning("Data file at " + storage.getAddressBookFilePath() + " could not be loaded."
+ " Will be starting with an empty AddressBook.");
initialData = new AddressBook();
predefinedAssignments = new PredefinedAssignmentsData();
}

return new ModelManager(initialData, userPrefs, readAssignmentOptional.get());
return new ModelManager(initialData, userPrefs, predefinedAssignments);
}

private void initLogging(Config config) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/seedu/address/logic/commands/AddCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class AddCommand extends Command {
+ PREFIX_PHONE + "PHONE "
+ PREFIX_EMAIL + "EMAIL "
+ PREFIX_ADDRESS + "ADDRESS "
+ PREFIX_TELEGRAM + "TELEGRAM "
+ "[" + PREFIX_TAG + "TAG]... "
+ PREFIX_GITHUB + "GITHUB\n"
+ "Example: " + COMMAND_WORD + " "
Expand Down
63 changes: 63 additions & 0 deletions src/main/java/seedu/address/logic/commands/FilterCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.TagContainsKeywordsPredicate;

/**
* Finds and lists all persons in address book whose tag equals to any of the specified tag.
* Tag name must be the same (case sensitive).
*/
public class FilterCommand extends Command {

public static final String COMMAND_WORD = "filter";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filter the list to show all contacts whose tag "
+ "contain any of the specified keywords (case-insensitive) and displays them as a list with index "
+ "numbers.\n"
+ "Parameters: " + PREFIX_TAG + "TAG" + "[" + PREFIX_TAG + "MORE_TAG]... "
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_TAG + "student "
+ PREFIX_TAG + "T02";

private final TagContainsKeywordsPredicate predicate;

public FilterCommand(TagContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
return new CommandResult(
String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof FilterCommand)) {
return false;
}

FilterCommand otherFilterCommand = (FilterCommand) other;
return predicate.equals(otherFilterCommand.predicate);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("predicate", predicate)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
Expand Down Expand Up @@ -81,6 +82,9 @@ public Command parseCommand(String userInput) throws ParseException {
case AddGradeCommand.COMMAND_WORD:
return new AddGradeCommandParser().parse(arguments);

case FilterCommand.COMMAND_WORD:
return new FilterCommandParser().parse(arguments);

default:
logger.finer("This user input caused a ParseException: " + userInput);
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/seedu/address/logic/parser/FilterCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import java.util.Set;
import java.util.stream.Stream;

import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.TagContainsKeywordsPredicate;
import seedu.address.model.tag.Tag;

/**
* Parses input arguments and creates a new FilterCommand object
*/
public class FilterCommandParser implements Parser<FilterCommand> {

/**
* Parses the given {@code String} of arguments in the context of the FilterCommand
* and returns a FilterCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public FilterCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_TAG);

if (!arePrefixesPresent(argMultimap, PREFIX_TAG) || !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}
Set<Tag> taglist = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));

return new FilterCommand(new TagContainsKeywordsPredicate(taglist));
}



/**
* Returns true if none of the prefixes contains empty {@code Optional} values in the given
* {@code ArgumentMultimap}.
*/
private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package seedu.address.model.person;

import java.util.Set;
import java.util.function.Predicate;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.tag.Tag;

/**
* Tests that a {@code Person}'s {@code Tag} matches any of the given tag.
*/
public class TagContainsKeywordsPredicate implements Predicate<Person> {

private final Set<Tag> keywords;

public TagContainsKeywordsPredicate(Set<Tag> keywords) {
this.keywords = keywords;
}
@Override
public boolean test(Person person) {
return keywords.stream().anyMatch(keyword -> person.getTags().contains(keyword));
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof TagContainsKeywordsPredicate)) {
return false;
}

TagContainsKeywordsPredicate otherTagContainsKeywordsPredicate = (TagContainsKeywordsPredicate) other;
return keywords.equals(otherTagContainsKeywordsPredicate.keywords);
}

@Override
public String toString() {
return new ToStringBuilder(this).add("keywords", keywords).toString();
}




}
6 changes: 3 additions & 3 deletions src/main/java/seedu/address/model/person/Telegram.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
*/
public class Telegram {

public static final String MESSAGE_CONSTRAINTS = "Telegram must start with a '@' and can only contain "
public static final String MESSAGE_CONSTRAINTS = "Telegram must start with a '@' and can only contain '_' & "
+ "alphanumeric characters";

/*
* The first character of the address must not be a whitespace,
* The first character of the telegram must not be a whitespace and must contain '@',
* otherwise " " (a blank string) becomes a valid input.
*/
public static final String VALIDATION_REGEX = "@[a-zA-Z0-9]+";
public static final String VALIDATION_REGEX = "@[a-zA-Z0-9_]+";

public final String value;

Expand Down
21 changes: 19 additions & 2 deletions src/main/java/seedu/address/ui/HelpWindow.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package seedu.address.ui;

import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Logger;

import javafx.fxml.FXML;
Expand All @@ -15,15 +19,17 @@
*/
public class HelpWindow extends UiPart<Stage> {

public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
public static final String USERGUIDE_URL = "https://ay2425s1-cs2103t-t11-2.github.io/tp/UserGuide.html";
public static final String HELP_MESSAGE = "Please refer to the user guide: " + USERGUIDE_URL;

private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";

@FXML
private Button copyButton;

@FXML
private Button openLinkButton;
@FXML
private Label helpMessage;

Expand Down Expand Up @@ -99,4 +105,15 @@ private void copyUrl() {
url.putString(USERGUIDE_URL);
clipboard.setContent(url);
}

/**
* Launches the URL of the user guide in the user's console
*
* @throws URISyntaxException
* @throws IOException
*/
@FXML
private void openUrl() throws URISyntaxException, IOException {
Desktop.getDesktop().browse(new URI(USERGUIDE_URL));
}
}
22 changes: 18 additions & 4 deletions src/main/resources/view/HelpWindow.css
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
#copyButton, #helpMessage {
#copyButton, #openLinkButton {
-fx-text-fill: white;
-fx-min-width: 80px;
}

#copyButton {
#helpMessage {
-fx-text-fill: white;
-fx-min-width: 100px;
}

#copyButton , #openLinkButton {
-fx-background-color: dimgray;
}

#copyButton:hover {
#copyButton:hover , #openLinkButton:hover {
-fx-background-color: gray;
-fx-border-color: white;
-fx-border-width: 0.5px;
}

#copyButton:focused , #openLinkButton:focused {
-fx-background-color: gray;
-fx-border-color: white;
-fx-border-width: 0.5px;
}

#copyButton:armed {
#copyButton:focused:armed , #openLinkButton:focused:armed {
-fx-background-color: darkgray;
}

Expand Down
9 changes: 7 additions & 2 deletions src/main/resources/view/HelpWindow.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.stage.Stage?>

<fx:root resizable="false" title="Help" type="javafx.stage.Stage" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1">
<fx:root resizable="false" title="Help" type="javafx.stage.Stage" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1">
<icons>
<Image url="@/images/help_icon.png" />
</icons>
Expand All @@ -19,7 +19,7 @@
<URL value="@HelpWindow.css" />
</stylesheets>

<HBox alignment="CENTER" fx:id="helpMessageContainer">
<HBox fx:id="helpMessageContainer" alignment="CENTER">
<children>
<Label fx:id="helpMessage" text="Label">
<HBox.margin>
Expand All @@ -31,6 +31,11 @@
<Insets left="5.0" />
</HBox.margin>
</Button>
<Button fx:id="openLinkButton" mnemonicParsing="false" onAction="#openUrl" text="Open URL">
<HBox.margin>
<Insets left="5.0" />
</HBox.margin>
</Button>
</children>
<opaqueInsets>
<Insets bottom="10.0" left="5.0" right="10.0" top="5.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"email" : "[email protected]",
"address" : "4th street",
"telegram": "@George",
"tags" : [ ],
"tags" : [ "husband" ],
"github" : "George"
} ]
}
Loading

0 comments on commit a8c2456

Please sign in to comment.