Skip to content

Commit

Permalink
Merge pull request #85 from jiakai-17/jiakai/implement-find-task
Browse files Browse the repository at this point in the history
feat: Implement Find Task
  • Loading branch information
HugeNoob authored Oct 18, 2023
2 parents e126f29 + c5f1d86 commit 2f98290
Show file tree
Hide file tree
Showing 15 changed files with 739 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/main/java/seedu/address/logic/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,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_TASKS_LISTED_OVERVIEW = "%1$d tasks listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";

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

import static java.util.Objects.requireNonNull;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.task.TaskContainsKeywordsPredicate;

/**
* Finds and lists all task in address book whose title or note contains any of the argument keywords.
* Keyword matching is case-insensitive.
*/
public class FindTaskCommand extends Command {

public static final String COMMAND_WORD = "findTask";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all tasks whose title or note contain any of "
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ "Example: " + COMMAND_WORD + " agenda budget";

private final TaskContainsKeywordsPredicate predicate;

public FindTaskCommand(TaskContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredTaskList(predicate);
return new CommandResult(
String.format(Messages.MESSAGE_TASKS_LISTED_OVERVIEW, model.getFilteredTaskList().size()));
}

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

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

FindTaskCommand otherFindTaskCommand = (FindTaskCommand) other;
return predicate.equals(otherFindTaskCommand.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 @@ -16,6 +16,7 @@
import seedu.address.logic.commands.EditPersonCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindPersonCommand;
import seedu.address.logic.commands.FindTaskCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListPersonCommand;
import seedu.address.logic.parser.exceptions.ParseException;
Expand Down Expand Up @@ -75,6 +76,9 @@ public Command parseCommand(String userInput) throws ParseException {
case AddTaskCommand.COMMAND_WORD:
return new AddTaskCommandParser().parse(arguments);

case FindTaskCommand.COMMAND_WORD:
return new FindTaskCommandParser().parse(arguments);

case ExitCommand.COMMAND_WORD:
return new ExitCommand();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import java.util.Arrays;

import seedu.address.logic.commands.FindTaskCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.task.TaskContainsKeywordsPredicate;

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

/**
* Parses the given {@code String} of arguments in the context of the FindTaskCommand
* and returns a FindTaskCommand object for execution.
*
* @throws ParseException if the user input does not conform the expected format
*/
public FindTaskCommand parse(String args) throws ParseException {
String trimmedArgs = args.trim();
if (trimmedArgs.isEmpty()) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindTaskCommand.MESSAGE_USAGE));
}

String[] taskKeywords = trimmedArgs.split("\\s+");

return new FindTaskCommand(new TaskContainsKeywordsPredicate(Arrays.asList(taskKeywords)));
}

}
43 changes: 25 additions & 18 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@
* The API of the Model component.
*/
public interface Model {
/** {@code Predicate} that always evaluate to true */
/**
* {@code Predicate} that always evaluate to true
*/
Predicate<Person> PREDICATE_SHOW_ALL_PERSONS = unused -> true;
Predicate<Task> PREDICATE_SHOW_ALL_TASKS = unused -> true;

/**
* Replaces user prefs data with the data in {@code userPrefs}.
* Returns the user prefs.
*/
void setUserPrefs(ReadOnlyUserPrefs userPrefs);
ReadOnlyUserPrefs getUserPrefs();

/**
* Returns the user prefs.
* Replaces user prefs data with the data in {@code userPrefs}.
*/
ReadOnlyUserPrefs getUserPrefs();
void setUserPrefs(ReadOnlyUserPrefs userPrefs);

/**
* Returns the user prefs' GUI settings.
Expand All @@ -46,15 +48,17 @@ public interface Model {
*/
void setAddressBookFilePath(Path addressBookFilePath);

/**
* Returns the AddressBook
*/
ReadOnlyAddressBook getAddressBook();

/**
* Replaces address book data with the data in {@code addressBook}.
*/
void setAddressBook(ReadOnlyAddressBook addressBook);

/** Returns the AddressBook */
ReadOnlyAddressBook getAddressBook();

//=========== Person Level Operations ==============================================================================
//=========== Person Level Operations ====================================================================

/**
* Returns true if a person with the same identity as {@code person} exists in the address book.
Expand All @@ -81,24 +85,27 @@ public interface Model {
/**
* Replaces the given person {@code target} with {@code editedPerson}.
* {@code target} must exist in the address book.
* The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
* The person identity of {@code editedPerson} must not be the same as another existing person
* in the address book.
*/
void setPerson(Person target, Person editedPerson);

/** Returns an unmodifiable view of the filtered person list */
/**
* Returns an unmodifiable view of the filtered person list
*/
ObservableList<Person> getFilteredPersonList();

/**
* Updates the filter of the filtered person list to filter by the given {@code predicate}.
*
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredPersonList(Predicate<Person> predicate);

//=========== Task Level Operations ================================================================================
//=========== Task-Level operations ======================================================================

/**
* Returns true if a task with the same title and note as {@code task} exists in
* the address book.
* Returns true if a task with the same title and note as {@code task} exists in the address book.
*/
boolean hasTask(Task task);

Expand All @@ -108,15 +115,15 @@ public interface Model {
*/
void addTask(Task task);

/** Returns an unmodifiable view of the filtered task list */
/**
* Returns an unmodifiable view of the filtered task list
*/
ObservableList<Task> getFilteredTaskList();

/**
* Updates the filter of the filtered task list to filter by the given
* {@code predicate}.
* Updates the filter of the filtered task list to filter by the given {@code predicate}.
*
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredTaskList(Predicate<Task> predicate);

}
26 changes: 14 additions & 12 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ public ModelManager() {
//=========== UserPrefs ==================================================================================

@Override
public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
requireNonNull(userPrefs);
this.userPrefs.resetData(userPrefs);
public ReadOnlyUserPrefs getUserPrefs() {
return userPrefs;
}

@Override
public ReadOnlyUserPrefs getUserPrefs() {
return userPrefs;
public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
requireNonNull(userPrefs);
this.userPrefs.resetData(userPrefs);
}

@Override
Expand Down Expand Up @@ -81,16 +81,16 @@ public void setAddressBookFilePath(Path addressBookFilePath) {
//=========== AddressBook ================================================================================

@Override
public void setAddressBook(ReadOnlyAddressBook addressBook) {
this.addressBook.resetData(addressBook);
public ReadOnlyAddressBook getAddressBook() {
return addressBook;
}

@Override
public ReadOnlyAddressBook getAddressBook() {
return addressBook;
public void setAddressBook(ReadOnlyAddressBook addressBook) {
this.addressBook.resetData(addressBook);
}

//=========== Person Level Operations ==============================================================================
//=========== Person-Level Operations ====================================================================

@Override
public boolean hasPerson(Person person) {
Expand Down Expand Up @@ -138,7 +138,7 @@ public void updateFilteredPersonList(Predicate<Person> predicate) {
filteredPersons.setPredicate(predicate);
}

//=========== Task Level Operations ================================================================================
//=========== Task-Level Operations ======================================================================

@Override
public boolean hasTask(Task task) {
Expand All @@ -152,7 +152,7 @@ public void addTask(Task task) {
updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS);
}

//=========== Filtered Task List Accessors =============================================================
//=========== Filtered Task List Accessors ===============================================================

/**
* Returns an unmodifiable view of the list of {@code Task} backed by the
Expand All @@ -170,6 +170,8 @@ public void updateFilteredTaskList(Predicate<Task> predicate) {
filteredTasks.setPredicate(predicate);
}

//=========== Object Overrides ===========================================================================

@Override
public boolean equals(Object other) {
if (other == this) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package seedu.address.model.task;

import java.util.List;
import java.util.function.Predicate;

import seedu.address.commons.util.StringUtil;
import seedu.address.commons.util.ToStringBuilder;

/**
* Tests that a {@code Task}'s {@code Note} matches any of the keywords given.
*/
public class NoteContainsKeywordsPredicate implements Predicate<Task> {
private final List<String> keywords;

public NoteContainsKeywordsPredicate(List<String> keywords) {
this.keywords = keywords;
}

@Override
public boolean test(Task task) {
return keywords
.stream()
.anyMatch(keyword -> StringUtil.containsWordIgnoreCase(task.getNote().toString(), keyword));
}

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

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

NoteContainsKeywordsPredicate otherNoteContainsKeywordsPredicate = (NoteContainsKeywordsPredicate) other;
return keywords.equals(otherNoteContainsKeywordsPredicate.keywords);
}

@Override
public String toString() {
return new ToStringBuilder(this).add("keywords", keywords).toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package seedu.address.model.task;

import java.util.List;
import java.util.function.Predicate;

import seedu.address.commons.util.ToStringBuilder;

/**
* Tests that a {@code Task}'s {@code Title} or {@code Note} matches any of the keywords given.
*/
public class TaskContainsKeywordsPredicate implements Predicate<Task> {
private final List<String> keywords;
private final TitleContainsKeywordsPredicate titlePredicate;
private final NoteContainsKeywordsPredicate notePredicate;

/**
* Constructs a {@code TaskContainsKeywordsPredicate} with the specified keywords.
*
* @param keywords A list of keywords to search for.
*/
public TaskContainsKeywordsPredicate(List<String> keywords) {
this.keywords = keywords;
this.titlePredicate = new TitleContainsKeywordsPredicate(keywords);
this.notePredicate = new NoteContainsKeywordsPredicate(keywords);
}

@Override
public boolean test(Task task) {
return titlePredicate.test(task) || notePredicate.test(task);
}

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

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

TaskContainsKeywordsPredicate otherTaskContainsKeywordsPredicate = (TaskContainsKeywordsPredicate) other;
return keywords.equals(otherTaskContainsKeywordsPredicate.keywords);
}

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

0 comments on commit 2f98290

Please sign in to comment.