Skip to content
This repository has been archived by the owner on Sep 14, 2023. It is now read-only.

Commit

Permalink
Merge pull request #93 from lhy-hoyin/branch-SortEvent
Browse files Browse the repository at this point in the history
New Feature: ShowNext Command
and code for upcoming event (not fully implemented yet)
  • Loading branch information
lhy-hoyin authored Mar 28, 2023
2 parents 6553c5a + 32506d8 commit d474ad2
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 26 deletions.
5 changes: 5 additions & 0 deletions src/main/java/ezschedule/logic/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public interface Logic {
*/
ReadOnlyScheduler getScheduler();

/**
* Returns an unmodifiable view of the upcoming list of events
*/
ObservableList<Event> getUpcomingEventList();

/**
* Returns an unmodifiable view of the list of events
*/
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/ezschedule/logic/LogicManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public ReadOnlyScheduler getScheduler() {
return model.getScheduler();
}

@Override
public ObservableList<Event> getUpcomingEventList() {
return model.getUpcomingEventList();
}

@Override
public ObservableList<Event> getEventList() {
return model.getEventList();
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/ezschedule/logic/commands/ShowNextCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ezschedule.logic.commands;

import static java.util.Objects.requireNonNull;

import ezschedule.commons.core.Messages;
import ezschedule.logic.commands.exceptions.CommandException;
import ezschedule.model.Model;
import ezschedule.model.event.UpcomingEventPredicate;

/**
* List the next (or next few) upcoming events.
* Completed events are not considered upcoming.
*/
public class ShowNextCommand extends Command {

public static final String COMMAND_WORD = "next";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Display upcoming events."
+ "\nCan be used without any parameters."
+ "\nParameter: COUNT (must be a positive integer)"
+ "\nExample: " + COMMAND_WORD + " 3";

private final UpcomingEventPredicate predicate;

public ShowNextCommand(UpcomingEventPredicate predicate) {
this.predicate = predicate;
}

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

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof ShowNextCommand // instanceof handles nulls
&& predicate.equals(((ShowNextCommand) other).predicate)); // state check
}
}
4 changes: 4 additions & 0 deletions src/main/java/ezschedule/logic/parser/SchedulerParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import ezschedule.logic.commands.HelpCommand;
import ezschedule.logic.commands.ListCommand;
import ezschedule.logic.commands.RecurCommand;
import ezschedule.logic.commands.ShowNextCommand;
import ezschedule.logic.parser.exceptions.ParseException;

/**
Expand Down Expand Up @@ -61,6 +62,9 @@ public Command parseCommand(String userInput) throws ParseException {
case ListCommand.COMMAND_WORD:
return new ListCommand();

case ShowNextCommand.COMMAND_WORD:
return new ShowNextCommandParser().parse(arguments);

case ExitCommand.COMMAND_WORD:
return new ExitCommand();

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

import ezschedule.commons.core.Messages;
import ezschedule.logic.commands.ShowNextCommand;
import ezschedule.logic.parser.exceptions.ParseException;
import ezschedule.model.event.UpcomingEventPredicate;

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

/**
* Parses the given {@code String} of arguments in the context of the ShowNextCommand
* and returns an ShowNextCommand object for execution.
*
* @throws ParseException if the user input does not conform the expected format
*/
@Override
public ShowNextCommand parse(String userInput) throws ParseException {
// No argument provided, just show the next one
if (userInput.isBlank()) {
return new ShowNextCommand(new UpcomingEventPredicate(1));
}

try {
int count = Integer.parseInt(userInput.trim());
if (count > 0) {
return new ShowNextCommand(new UpcomingEventPredicate(count));
}
} catch (NumberFormatException e) {
// Empty here; another exception is throw outside.
}

throw new ParseException(
String.format(Messages.MESSAGE_INVALID_COMMAND_FORMAT, ShowNextCommand.MESSAGE_USAGE));
}
}
6 changes: 6 additions & 0 deletions src/main/java/ezschedule/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,17 @@ public interface Model {
*/
void setEvent(Event target, Event editedEvent);

/**
* Returns an unmodifiable view of the upcoming event list
*/
ObservableList<Event> getUpcomingEventList();

/**
* Returns an unmodifiable view of the event list
*/
ObservableList<Event> getEventList();


/**
* Returns an unmodifiable view of the filtered event list
*/
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/ezschedule/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class ModelManager implements Model {
private final FilteredList<Event> filteredEvents;

/**
* Initializes a ModelManager with the given addressBook and userPrefs.
* Initializes a ModelManager with the given scheduler and userPrefs.
*/
public ModelManager(ReadOnlyScheduler scheduler, ReadOnlyUserPrefs userPrefs) {
requireAllNonNull(scheduler, userPrefs);
Expand Down Expand Up @@ -120,7 +120,16 @@ public void setEvent(Event target, Event editedEvent) {

/**
* Returns an unmodifiable view of the list of {@code Event} backed by the internal list of
* {@code versionedScheduler}
* {@code scheduler}
*/
@Override
public ObservableList<Event> getUpcomingEventList() {
return scheduler.getUpcomingEvents();
}

/**
* Returns an unmodifiable view of the list of {@code Event} backed by the internal list of
* {@code scheduler}
*/
@Override
public ObservableList<Event> getEventList() {
Expand Down
38 changes: 37 additions & 1 deletion src/main/java/ezschedule/model/Scheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@

import ezschedule.model.event.Event;
import ezschedule.model.event.UniqueEventList;
import ezschedule.model.event.UpcomingEventPredicate;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;

/**
* Wraps all data at the scheduler level
* Duplicates are not allowed (by .isSameEvent comparison)
*/
public class Scheduler implements ReadOnlyScheduler {
private static final int DISPLAY_UPCOMING_COUNT = 1;
private static final UpcomingEventPredicate predicate = new UpcomingEventPredicate(DISPLAY_UPCOMING_COUNT);

private final UniqueEventList events;

private FilteredList<Event> upcomingEvents;

/*
* The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
* between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
Expand All @@ -27,7 +33,28 @@ public class Scheduler implements ReadOnlyScheduler {
events = new UniqueEventList();
}

public Scheduler() {}
/**
* Construct an instance of Scheduler object.
* Listeners are attached in here.
*/
public Scheduler() {
upcomingEvents = new FilteredList<>(getEventList());

// Attach a listener to auto-sort events in chronological order
events.addListChangeListener(c -> {
while (c.next()) {
if (!c.wasPermutated()) {
events.sortByChronologicalOrder();
}
}
});

events.addListChangeListener(c -> {
while (c.next()) { /* Do nothing */ }
upcomingEvents.setPredicate(predicate);
});

}

/**
* Creates a Scheduler using the Events in the {@code toBeCopied}
Expand Down Expand Up @@ -99,6 +126,15 @@ public void removeEvent(Event key) {
events.remove(key);
}

/**
* Returns the list of upcoming {@code Event}
*
* @return
*/
public FilteredList<Event> getUpcomingEvents() {
return upcomingEvents;
}

//// util methods

@Override
Expand Down
25 changes: 18 additions & 7 deletions src/main/java/ezschedule/model/event/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,24 @@ public Time getEndTime() {
}

public String getCompletedStatus() {
return date.isPastDate()
? "Event completed"
: date.isFutureDate()
? ""
: endTime.isPastTime()
? "Event completed"
: "";
return isCompleted() ? "Event completed" : "";
}

/**
* Returns true if the event has been completed/is over.
*
* @return true if event is completed.
*/
public boolean isCompleted() {
if (date.isPastDate()) {
return true; // Event is before today
} else if (date.isFutureDate()) {
return false; // Event is after today
} else {
// Event is sometime today
// Is current time passed the event end time?
return endTime.isPastTime();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import ezschedule.commons.util.StringUtil;

/**
* Tests that a {@code Event}'s {@code Name} matches any of the keywords given.
* Tests that an {@code Event}'s {@code Name} matches any of the keywords given.
*/
public class EventContainsKeywordsPredicate implements Predicate<Event> {

Expand Down
31 changes: 16 additions & 15 deletions src/main/java/ezschedule/model/event/UniqueEventList.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,6 @@ public class UniqueEventList implements Iterable<Event> {
private final ObservableList<Event> internalUnmodifiableList =
FXCollections.unmodifiableObservableList(internalList);

/**
* Constructor of UniqueEventList.
* Attaches a listener to sort the list of events in chronological order whenever its changed.
*/
public UniqueEventList() {
// Auto-sort whenever a list is changed
internalList.addListener((ListChangeListener<Event>) c -> {
while (c.next()) {
if (!c.wasPermutated()) {
FXCollections.sort(internalList);
}
}
});
}

/**
* Returns true if the list contains an equivalent event as the given argument.
*/
Expand All @@ -61,6 +46,22 @@ public boolean existsAtTime(Event toCheck) {
return internalList.stream().anyMatch(toCheck::isEventOverlap);
}

/**
* Attach {@code listener}, which is called whenever internalList is changed.
*
* @param listener A ListChangeListener to be called.
*/
public void addListChangeListener(ListChangeListener<Event> listener) {
internalList.addListener(listener);
}

/**
* Sorts all events in chronological order.
*/
public void sortByChronologicalOrder() {
FXCollections.sort(internalList);
}

/**
* Adds an event to the list.
* The event must not already exist in the list.
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/ezschedule/model/event/UpcomingEventPredicate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ezschedule.model.event;

import java.util.function.Predicate;

/**
* Tests that an {@code Event} is one of the upcoming events.
* Only the first {@code count} number of upcoming events are considered.
*/
public class UpcomingEventPredicate implements Predicate<Event> {

private int upcomingCount;

public UpcomingEventPredicate(int count) {
upcomingCount = count;
}

// Events should be in chronological order
@Override
public boolean test(Event event) {
if (event.isCompleted()) {
return false;
}

return upcomingCount-- > 0;
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof UpcomingEventPredicate // instanceof handles nulls
&& upcomingCount == ((UpcomingEventPredicate) other).upcomingCount); // state check
}
}
5 changes: 5 additions & 0 deletions src/test/java/ezschedule/logic/commands/AddCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ public void setEvent(Event target, Event editedEvent) {
throw new AssertionError("This method should not be called.");
}

@Override
public ObservableList<Event> getUpcomingEventList() {
throw new AssertionError("This method should not be called.");
}

@Override
public ObservableList<Event> getEventList() {
throw new AssertionError("This method should not be called.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import ezschedule.logic.commands.FindCommand.FindEventDescriptor;
import ezschedule.logic.commands.HelpCommand;
import ezschedule.logic.commands.ListCommand;
import ezschedule.logic.commands.ShowNextCommand;
import ezschedule.logic.parser.exceptions.ParseException;
import ezschedule.model.event.Event;
import ezschedule.model.event.Name;
Expand Down Expand Up @@ -86,6 +87,12 @@ public void parseCommand_list() throws Exception {
assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
}

@Test
public void parseCommand_showNext() throws Exception {
assertTrue(parser.parseCommand(ShowNextCommand.COMMAND_WORD) instanceof ShowNextCommand);
assertTrue(parser.parseCommand(ShowNextCommand.COMMAND_WORD + " 3") instanceof ShowNextCommand);
}

@Test
public void parseCommand_unrecognisedInput_throwsParseException() {
assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
Expand Down

0 comments on commit d474ad2

Please sign in to comment.