Skip to content

Commit

Permalink
Merge pull request #44 from CS2103AUG2016-W10-C2/33-list-entries-due-…
Browse files Browse the repository at this point in the history
…in-range

33 list entries due in range
  • Loading branch information
joeleba authored Oct 18, 2016
2 parents 9cee882 + 3c4f32e commit 9ef5bd0
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 73 deletions.
56 changes: 50 additions & 6 deletions src/main/java/seedu/address/logic/commands/ListCommand.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package seedu.address.logic.commands;

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

import seedu.address.model.PredicateBuilder;
import seedu.address.model.task.Entry;

/**
* Lists all persons in the address book to the user.
Expand All @@ -12,22 +17,51 @@ public class ListCommand extends Command {
public static final String MESSAGE_SUCCESS = "Listed all entries";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": List all entries whose titles contain any of "
+ "the specified keywords (case-sensitive) and displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ "Example: " + COMMAND_WORD + " alice bob charlie";
+ "the specified keywords (case-sensitive), or with deadlines before/after certain dates"
+ "and displays them as a list with index numbers.\n"
+ "Parameters: [after/YYYY-MM-DD] [before/YYYY-MM-DD] [KEYWORDS]\n"
+ "Example: " + COMMAND_WORD + " after/2016-10-10 alice bob charlie";

public static final String AFTER_FLAG = "after/";
public static final String BEFORE_FLAG = "before/";

private Set<String> keywords;
private LocalDateTime startDate;
private LocalDateTime endDate;

private PredicateBuilder predicateBuilder;

private final Set<String> keywords;
public ListCommand() {}

/**
* Convenient constructor
* @param keywords
*/
public ListCommand(Set<String> keywords) {
this.keywords = keywords;
this.predicateBuilder = new PredicateBuilder();
}

public void setKeywords(Set<String> keywords) {
this.keywords = keywords;
}

public void setStartDate(LocalDateTime startDate) {
this.startDate = startDate;
}

public void setEndDate(LocalDateTime endDate) {
this.endDate = endDate;
}

@Override
public CommandResult execute() {
if (keywords.isEmpty()) {
if (isListAll()) {
return showAll();
} else {
model.updateFilteredPersonList(keywords);
Predicate<Entry> predicate = predicateBuilder.buildPredicate(keywords, startDate, endDate);
model.updateFilteredEntryListPredicate(predicate);

return new CommandResult(getMessageForPersonListShownSummary(model.getFilteredPersonList().size()));
}
}
Expand All @@ -36,4 +70,14 @@ private CommandResult showAll() {
model.updateFilteredListToShowAll();
return new CommandResult(MESSAGE_SUCCESS);
}

/**
* Return whether this list command is a "list all"
*
*/
private boolean isListAll() {
return (keywords == null || keywords.isEmpty())
&& startDate == null
&& endDate == null;
}
}
62 changes: 54 additions & 8 deletions src/main/java/seedu/address/logic/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.logic.commands.ListCommand.AFTER_FLAG;
import static seedu.address.logic.commands.ListCommand.BEFORE_FLAG;

/**
* Parses user input.
Expand All @@ -24,8 +26,11 @@ public class Parser {

private static final Pattern PERSON_INDEX_ARGS_FORMAT = Pattern.compile("(?<targetIndex>.+)");

private static final Pattern KEYWORDS_ARGS_FORMAT =
Pattern.compile("(?<keywords>\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace
// TODO: Use tokenizer for these
private static final Pattern LIST_ARGS_FORMAT =
Pattern.compile("(?<startDate>\\s*" + AFTER_FLAG + "\\d{4}-\\d{1,2}-\\d{1,2})?"
+ "(?<endDate>\\s*" + BEFORE_FLAG + "\\d{4}-\\d{1,2}-\\d{1,2})?"
+ "(?<keywords>\\s*\\S*(?:\\s+\\S+)*)"); // zero or more keywords separated by whitespace

private static final Pattern FLOATING_TASK_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes
Pattern.compile("(?<title>[^/]+)"
Expand Down Expand Up @@ -205,6 +210,34 @@ private static LocalDateTime getDeadlineFromArgument(String deadlineArguments) t
final List<String> cleanedStrings = Arrays.asList(deadlineArguments.replaceFirst(" deadline/", "").split(" "));
return LocalDateTime.parse(cleanedStrings.get(0) + "T" + cleanedStrings.get(1) + ":00");
}

/**
* Parse LocalDateTime of start date from an input string
* string. Format: YYYY-MM-DD
*/
private static LocalDateTime getStartDateFromArgument(String dateTime) throws IllegalValueException {
if (dateTime == null || dateTime.isEmpty()) {
return null;
}

// remove the tag.
final String cleanedString = dateTime.trim().replaceFirst(AFTER_FLAG, "") + "T" + "00:00:00";
return LocalDateTime.parse(cleanedString);
}

/**
* Parse LocalDateTime of end start from an input string
* string. Format: YYYY-MM-DD
*/
private static LocalDateTime getEndDateFromArgument(String dateTime) throws IllegalValueException {
if (dateTime == null || dateTime.isEmpty()) {
return null;
}

// remove the tag.
final String cleanedString = dateTime.trim().replaceFirst(BEFORE_FLAG, "") + "T" + "23:59:59";
return LocalDateTime.parse(cleanedString);
}

/**
* Parses arguments in the context of the delete task command.
Expand Down Expand Up @@ -350,18 +383,31 @@ private Optional<Integer> parseIndex(String command) {
private Command prepareList(String args) {
// Guard statement
if (args.isEmpty()) {
return new ListCommand(new HashSet<>());
return new ListCommand();
}

final Matcher matcher = KEYWORDS_ARGS_FORMAT.matcher(args.trim());
final Matcher matcher = LIST_ARGS_FORMAT.matcher(args.trim());
if (!matcher.matches()) {
return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListCommand.MESSAGE_USAGE));
}

// keywords delimited by whitespace
final String[] keywords = matcher.group("keywords").split("\\s+");
final Set<String> keywordSet = new HashSet<>(Arrays.asList(keywords));
return new ListCommand(keywordSet);
try {
final LocalDateTime startDate = getStartDateFromArgument(matcher.group("startDate"));
final LocalDateTime endDate = getEndDateFromArgument(matcher.group("endDate"));
// keywords delimited by whitespace
String[] keywords = matcher.group("keywords").trim().split("\\s+");

Set<String> keywordSet = new HashSet<>(Arrays.asList(keywords));
keywordSet.removeIf(s -> s.equals(""));

ListCommand listCommand = new ListCommand(keywordSet);
listCommand.setStartDate(startDate);
listCommand.setEndDate(endDate);

return listCommand;
} catch (IllegalValueException ive) {
return new IncorrectCommand(ive.getMessage());
}
}

}
8 changes: 5 additions & 3 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import seedu.address.model.task.Update;
import seedu.address.model.tag.UniqueTagList.DuplicateTagException;

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

/**
* The API of the Model component.
Expand Down Expand Up @@ -42,9 +44,9 @@ void editTask(Update update)
/** Updates the filter of the filtered task list to show all persons */
void updateFilteredListToShowAll();

/** Updates the filter of the filtered task list to filter by the given keywords*/
void updateFilteredPersonList(Set<String> keywords);

/** Updates the filter of the filtered task list*/
void updateFilteredEntryListPredicate(Predicate<Entry> predicate);
/** Marks the given task.
* @throws DuplicateTaskException */
void markTask(Entry entryToMark) throws UniquePersonList.PersonNotFoundException, DuplicateTaskException;
Expand Down
67 changes: 11 additions & 56 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package seedu.address.model;

import javafx.collections.transformation.FilteredList;

import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.core.UnmodifiableObservableList;
import seedu.address.commons.util.StringUtil;
import seedu.address.commons.events.model.AddressBookChangedEvent;
import seedu.address.commons.core.ComponentManager;
import seedu.address.model.task.Entry;
import seedu.address.model.task.Deadline;
import seedu.address.model.task.FloatingTask;
import seedu.address.model.task.UniquePersonList;
import seedu.address.model.task.UniquePersonList.DuplicateTaskException;
import seedu.address.model.task.UniquePersonList.PersonNotFoundException;
Expand All @@ -15,7 +18,9 @@
import seedu.address.model.task.Update;
import seedu.address.model.tag.UniqueTagList.DuplicateTagException;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.function.Predicate;
import java.util.logging.Logger;

/**
Expand Down Expand Up @@ -134,64 +139,14 @@ public void updateFilteredListToShowAll() {
}

@Override
public void updateFilteredPersonList(Set<String> keywords){
updateFilteredPersonList(new PredicateExpression(new NameQualifier(keywords)));
}

private void updateFilteredPersonList(Expression expression) {
filteredPersons.setPredicate(expression::satisfies);
}

//========== Inner classes/interfaces used for filtering ==================================================

interface Expression {
boolean satisfies(Entry person);
String toString();
public void updateFilteredEntryListPredicate(Predicate<Entry> predicate) {
updateFilteredPersonList(predicate);
}

private class PredicateExpression implements Expression {

private final Qualifier qualifier;

PredicateExpression(Qualifier qualifier) {
this.qualifier = qualifier;
}

@Override
public boolean satisfies(Entry person) {
return qualifier.run(person);
}

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

interface Qualifier {
boolean run(Entry person);
String toString();

private void updateFilteredPersonList(Predicate<Entry> predicate) {
filteredPersons.setPredicate(predicate);
}

private class NameQualifier implements Qualifier {
private Set<String> nameKeyWords;

NameQualifier(Set<String> nameKeyWords) {
this.nameKeyWords = nameKeyWords;
}

@Override
public boolean run(Entry entry) {
return nameKeyWords.stream()
.filter(keyword -> StringUtil.containsIgnoreCase(entry.getTitle().fullTitle, keyword))
.findAny()
.isPresent();
}

@Override
public String toString() {
return "name=" + String.join(", ", nameKeyWords);
}
}


}
Loading

0 comments on commit 9ef5bd0

Please sign in to comment.