Skip to content

Commit

Permalink
Merge pull request #39 from yongxiangng/branch-feature-details
Browse files Browse the repository at this point in the history
Implement details command
  • Loading branch information
nzixuan authored Oct 6, 2021
2 parents 8066d04 + ff95db4 commit b5fa26d
Show file tree
Hide file tree
Showing 19 changed files with 461 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/main/java/seedu/address/commons/core/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class Messages {
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
public static final String MESSAGE_PERSON_DETAILS_FOUND = "Showing details of %1$s";
public static final String MESSAGE_PERSON_DETAILS_NOT_FOUND = "Person with name %1$s not found!";

}
12 changes: 10 additions & 2 deletions src/main/java/seedu/address/logic/commands/CommandResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,25 @@ public class CommandResult {
/** The application should exit. */
private final boolean exit;

/** The application should show the details component in the ui. */
private final boolean showDetails;

/**
* Constructs a {@code CommandResult} with the specified fields.
*/
public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean showDetails) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
this.showDetails = showDetails;
}

/**
* Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser) {
this(feedbackToUser, false, false);
this(feedbackToUser, false, false, false);
}

public String getFeedbackToUser() {
Expand All @@ -46,6 +50,10 @@ public boolean isExit() {
return exit;
}

public boolean isShowDetails() {
return showDetails;
}

@Override
public boolean equals(Object other) {
if (other == this) {
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/seedu/address/logic/commands/DetailsCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
import seedu.address.model.person.NameEqualKeywordPredicate;

/**
* Finds and displays the details of person whose name matches the keyword exactly.
* Keyword matching is exact and case sensitive.
*/
public class DetailsCommand extends Command {

public static final String COMMAND_WORD = "details";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Displays the details of a member from the "
+ "specified keywords (case-sensitive and exact match).\n"
+ "Parameters: NAME (case-sensitive)\n"
+ "Example: " + COMMAND_WORD + " Xiao Ming";

private final NameEqualKeywordPredicate predicate;

public DetailsCommand(NameEqualKeywordPredicate predicate) {
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
assert model.getFilteredPersonList().size() < 2;
if (model.getFilteredPersonList().size() == 0) {
return new CommandResult(
String.format(Messages.MESSAGE_PERSON_DETAILS_NOT_FOUND, predicate),
false, false, true);
} else {
return new CommandResult(
String.format(Messages.MESSAGE_PERSON_DETAILS_FOUND, predicate),
false, false, true);
}
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof DetailsCommand // instanceof handles nulls
&& predicate.equals(((DetailsCommand) other).predicate)); // state check
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ExitCommand extends Command {

@Override
public CommandResult execute(Model model) {
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public class HelpCommand extends Command {

@Override
public CommandResult execute(Model model) {
return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.DetailsCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindCommand;
Expand Down Expand Up @@ -53,6 +54,9 @@ public Command parseCommand(String userInput) throws ParseException {
case DeleteCommand.COMMAND_WORD:
return new DeleteCommandParser().parse(arguments);

case DetailsCommand.COMMAND_WORD:
return new DetailsCommandParser().parse(arguments);

case ClearCommand.COMMAND_WORD:
return new ClearCommand();

Expand Down
30 changes: 30 additions & 0 deletions src/main/java/seedu/address/logic/parser/DetailsCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package seedu.address.logic.parser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import seedu.address.logic.commands.DetailsCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.Name;
import seedu.address.model.person.NameEqualKeywordPredicate;

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

/**
* Parses the given {@code String} of arguments in the context of the DetailsCommand
* and returns a DetailsCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public DetailsCommand parse(String args) throws ParseException {
try {
Name name = ParserUtil.parseName(args);
return new DetailsCommand(new NameEqualKeywordPredicate(name));
} catch (ParseException pe) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, DetailsCommand.MESSAGE_USAGE));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package seedu.address.model.person;

import java.util.function.Predicate;

/**
* Tests that a {@code Person}'s {@code Name} matches the keyword given exactly.
*/
public class NameEqualKeywordPredicate implements Predicate<Person> {
private final Name keyword;

public NameEqualKeywordPredicate(Name keyword) {
this.keyword = keyword;
}

@Override
public boolean test(Person person) {
return keyword.equals(person.getName());
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof NameEqualKeywordPredicate // instanceof handles nulls
&& keyword.equals(((NameEqualKeywordPredicate) other).keyword)); // state check
}

@Override
public String toString() {
return this.keyword.toString();
}

}
2 changes: 2 additions & 0 deletions src/main/java/seedu/address/ui/MainWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ private CommandResult executeCommand(String commandText) throws CommandException
handleExit();
}

personListPanel.setShowDetails(commandResult.isShowDetails());

return commandResult;
} catch (CommandException | ParseException e) {
logger.info("Invalid command: " + commandText);
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/seedu/address/ui/PersonDetailsCard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package seedu.address.ui;

import java.util.Comparator;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import seedu.address.model.person.Person;

/**
* An UI component that displays the detailed information of a {@code Person}.
*/
public class PersonDetailsCard extends UiPart<Region> {

private static final String FXML = "PersonDetailsCard.fxml";

/**
* Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
* As a consequence, UI elements' variable names cannot be set to such keywords
* or an exception will be thrown by JavaFX during runtime.
*
* @see <a href="https://github.com/se-edu/addressbook-level4/issues/336">The issue on AddressBook level 4</a>
*/

public final Person person;

@FXML
private HBox cardPane;
@FXML
private Label name;
@FXML
private Label phone;
@FXML
private Label address;
@FXML
private Label email;
@FXML
private FlowPane tags;

/**
* Creates a {@code PersonDetailsCard} with the given {@code Person}.
*/
public PersonDetailsCard(Person person) {
super(FXML);
this.person = person;
name.setText(person.getName().fullName);
phone.setText(person.getPhone().value);
address.setText(person.getAddress().value);
email.setText(person.getEmail().value);
person.getTags().stream()
.sorted(Comparator.comparing(tag -> tag.tagName))
.forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
}

@Override
public boolean equals(Object other) {
// short circuit if same object
if (other == this) {
return true;
}

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

// state check
PersonDetailsCard card = (PersonDetailsCard) other;
return person.equals(card.person);
}
}
12 changes: 12 additions & 0 deletions src/main/java/seedu/address/ui/PersonListPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
public class PersonListPanel extends UiPart<Region> {
private static final String FXML = "PersonListPanel.fxml";
private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
private boolean showDetails = false;

@FXML
private ListView<Person> personListView;
Expand All @@ -29,6 +30,15 @@ public PersonListPanel(ObservableList<Person> personList) {
personListView.setCellFactory(listView -> new PersonListViewCell());
}

/**
* Sets the details field to parameter passed.
*
* @param showDetails boolean value to show details.
*/
public void setShowDetails(boolean showDetails) {
this.showDetails = showDetails;
}

/**
* Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}.
*/
Expand All @@ -40,6 +50,8 @@ protected void updateItem(Person person, boolean empty) {
if (empty || person == null) {
setGraphic(null);
setText(null);
} else if (showDetails) {
setGraphic(new PersonDetailsCard(person).getRoot());
} else {
setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
}
Expand Down
40 changes: 40 additions & 0 deletions src/main/resources/view/PersonDetailsCard.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>

<HBox id="cardPane" fx:id="cardPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<GridPane HBox.hgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10" prefWidth="150" />
</columnConstraints>
<VBox alignment="CENTER_LEFT" minHeight="105" GridPane.columnIndex="0">
<padding>
<Insets bottom="5" left="15" right="5" top="5" />
</padding>
<HBox alignment="CENTER_LEFT" spacing="5">
<Label fx:id="name" styleClass="cell_big_label" text="\$first" />
<Label fx:id="id" styleClass="cell_big_label" text="details">
<minWidth>
<!-- Ensures that the label text is never truncated -->
<Region fx:constant="USE_PREF_SIZE" />
</minWidth>
</Label>
</HBox>
<FlowPane fx:id="tags" />
<Label fx:id="phone" styleClass="cell_small_label" text="\$phone" />
<Label fx:id="address" styleClass="cell_small_label" text="\$address" />
<Label fx:id="email" styleClass="cell_small_label" text="\$email" />
</VBox>
<rowConstraints>
<RowConstraints />
</rowConstraints>
</GridPane>
</HBox>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void equals() {

// same values -> returns true
assertTrue(commandResult.equals(new CommandResult("feedback")));
assertTrue(commandResult.equals(new CommandResult("feedback", false, false)));
assertTrue(commandResult.equals(new CommandResult("feedback", false, false, false)));

// same object -> returns true
assertTrue(commandResult.equals(commandResult));
Expand All @@ -29,10 +29,10 @@ public void equals() {
assertFalse(commandResult.equals(new CommandResult("different")));

// different showHelp value -> returns false
assertFalse(commandResult.equals(new CommandResult("feedback", true, false)));
assertFalse(commandResult.equals(new CommandResult("feedback", true, false, false)));

// different exit value -> returns false
assertFalse(commandResult.equals(new CommandResult("feedback", false, true)));
assertFalse(commandResult.equals(new CommandResult("feedback", false, true, false)));
}

@Test
Expand All @@ -46,9 +46,9 @@ public void hashcode() {
assertNotEquals(commandResult.hashCode(), new CommandResult("different").hashCode());

// different showHelp value -> returns different hashcode
assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false).hashCode());
assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", true, false, false).hashCode());

// different exit value -> returns different hashcode
assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true).hashCode());
assertNotEquals(commandResult.hashCode(), new CommandResult("feedback", false, true, false).hashCode());
}
}
Loading

0 comments on commit b5fa26d

Please sign in to comment.