From 77a36350c6ca65e3601551477ea56d4b48a0f4a9 Mon Sep 17 00:00:00 2001 From: pangjiahao Date: Sun, 28 Oct 2018 20:59:00 +0800 Subject: [PATCH] Add a prototype calendar, using jfxtras library (#57) * Add a prototype calendar, using jfxtras library CalendarDisplay: The new class that extends UiPart add the calendarDisplay to the MainWIndow * merge calendarDisplay UI into existing ui rename CalendarEvent.getDescription to CalendarEvent.getDescriptionObject add functionality so ui will update when user updates calendarEvents fix calendar losing focus on toggling view --- build.gradle | 1 + .../address/logic/commands/EditCommand.java | 2 +- .../model/calendarevent/CalendarEvent.java | 77 ++++++- .../storage/XmlAdaptedCalendarEvent.java | 2 +- .../seedu/address/ui/CalendarDisplay.java | 197 ++++++++++++++++++ .../seedu/address/ui/CalendarEventCard.java | 2 +- .../java/seedu/address/ui/MainWindow.java | 7 + src/main/resources/view/CalendarDisplay.fxml | 8 + src/main/resources/view/MainWindow.fxml | 5 + .../guihandles/CalendarEventCardHandle.java | 2 +- .../storage/XmlAdaptedCalendarEventTest.java | 2 +- .../testutil/CalendarEventBuilder.java | 2 +- .../testutil/EditPersonDescriptorBuilder.java | 2 +- .../seedu/address/testutil/PersonUtil.java | 2 +- .../address/ui/testutil/GuiTestAssert.java | 2 +- .../systemtests/FindCommandSystemTest.java | 2 +- 16 files changed, 301 insertions(+), 14 deletions(-) create mode 100644 src/main/java/seedu/address/ui/CalendarDisplay.java create mode 100644 src/main/resources/view/CalendarDisplay.fxml diff --git a/build.gradle b/build.gradle index 37cb6c12d1df..eb4a9ea52c1d 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,7 @@ dependencies { compile 'com.joestelmach:natty:0.13' compile 'me.xdrop:fuzzywuzzy:1.1.10' + compile group: 'org.jfxtras', name: 'jfxtras-agenda', version: '9.0-r1-SNAPSHOT' implementation group: 'org.controlsfx', name: 'controlsfx', version: '8.40.11' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.7.0' diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index afd310453fbf..3efaa23464a8 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -101,7 +101,7 @@ private static CalendarEvent createEditedCalendarEvent(CalendarEvent calendarEve Title updatedName = editCalendarEventDescriptor.getTitle().orElse(calendarEventToEdit.getTitle()); Description updatedDescription = - editCalendarEventDescriptor.getDescription().orElse(calendarEventToEdit.getDescription()); + editCalendarEventDescriptor.getDescription().orElse(calendarEventToEdit.getDescriptionObject()); DateTime updatedStart = editCalendarEventDescriptor.getStart().orElse(calendarEventToEdit.getStart()); DateTime updatedEnd = editCalendarEventDescriptor.getEnd().orElse(calendarEventToEdit.getEnd()); diff --git a/src/main/java/seedu/address/model/calendarevent/CalendarEvent.java b/src/main/java/seedu/address/model/calendarevent/CalendarEvent.java index 05e6d449fcb2..80d029c9851e 100644 --- a/src/main/java/seedu/address/model/calendarevent/CalendarEvent.java +++ b/src/main/java/seedu/address/model/calendarevent/CalendarEvent.java @@ -2,18 +2,22 @@ import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import java.time.LocalDateTime; +import java.time.temporal.Temporal; +import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.Objects; import java.util.Set; +import jfxtras.scene.control.agenda.Agenda; import seedu.address.model.tag.Tag; /** * Represents a Calendar Event in the scheduler. * Guarantees: details are present and not null, field values are validated, immutable. */ -public class CalendarEvent { +public class CalendarEvent extends Agenda.AppointmentImplLocal { // Identity fields private final Title title; @@ -24,6 +28,8 @@ public class CalendarEvent { private final DateTimeInfo dateTimeInfo; private final Set tags = new HashSet<>(); + private boolean isWholeDay; + /** * Every field must be present and not null. */ @@ -34,13 +40,76 @@ public CalendarEvent(Title title, Description description, DateTimeInfo dateTime this.dateTimeInfo = dateTimeInfo; this.venue = venue; this.tags.addAll(tags); + + // Appointment variables + this.isWholeDay = false; } public Title getTitle() { return title; } - public Description getDescription() { + @Override + public Boolean isWholeDay() { + return false; + } + + @Override + public void setWholeDay(Boolean b) { + this.isWholeDay = b; + } + + @Override + public String getSummary() { + return null; + } + + @Override + public void setSummary(String s) { + + } + + @Override + public String getDescription() { + return description.toString(); + } + + @Override + public void setDescription(String s) { + + } + + @Override + public String getLocation() { + return this.venue.toString(); + } + + @Override + public void setLocation(String s) { + + } + + // TODO: set up appointment groups + @Override + public Agenda.AppointmentGroup getAppointmentGroup() { + return null; + } + + @Override + public void setAppointmentGroup(Agenda.AppointmentGroup s) { + + } + + public LocalDateTime getStartLocalDateTime() { + return this.dateTimeInfo.start.localDateTime; + } + + @Override + public LocalDateTime getEndLocalDateTime() { + return this.dateTimeInfo.end.localDateTime; + } + + public Description getDescriptionObject() { return description; } @@ -95,7 +164,7 @@ public boolean equals(Object other) { CalendarEvent otherCalendarEvent = (CalendarEvent) other; return otherCalendarEvent.getTitle().equals(getTitle()) - && otherCalendarEvent.getDescription().equals(getDescription()) + && otherCalendarEvent.getDescriptionObject().equals(getDescriptionObject()) && otherCalendarEvent.getStart().equals(getStart()) && otherCalendarEvent.getEnd().equals(getEnd()) && otherCalendarEvent.getVenue().equals(getVenue()) @@ -114,7 +183,7 @@ public String toString() { builder.append(" Title: ") .append(getTitle()) .append(" Description: ") - .append(getDescription()) + .append(getDescriptionObject()) .append(" Start Date & Time: ") .append(getStart()) .append(" End Date & Time: ") diff --git a/src/main/java/seedu/address/storage/XmlAdaptedCalendarEvent.java b/src/main/java/seedu/address/storage/XmlAdaptedCalendarEvent.java index b381fda2b6cc..e5e8f1e69b54 100644 --- a/src/main/java/seedu/address/storage/XmlAdaptedCalendarEvent.java +++ b/src/main/java/seedu/address/storage/XmlAdaptedCalendarEvent.java @@ -68,7 +68,7 @@ public XmlAdaptedCalendarEvent(String title, String description, String start, S */ public XmlAdaptedCalendarEvent(CalendarEvent source) { title = source.getTitle().value; - description = source.getDescription().value; + description = source.getDescriptionObject().value; start = source.getStart().toInputFormat(); end = source.getEnd().toInputFormat(); venue = source.getVenue().value; diff --git a/src/main/java/seedu/address/ui/CalendarDisplay.java b/src/main/java/seedu/address/ui/CalendarDisplay.java new file mode 100644 index 000000000000..35cb4a20a5a2 --- /dev/null +++ b/src/main/java/seedu/address/ui/CalendarDisplay.java @@ -0,0 +1,197 @@ +package seedu.address.ui; + +import static javafx.scene.input.KeyEvent.KEY_PRESSED; + +import java.time.LocalDateTime; +import java.util.logging.Logger; + +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.util.Callback; +import jfxtras.internal.scene.control.skin.agenda.AgendaDaySkin; +import jfxtras.internal.scene.control.skin.agenda.AgendaWeekSkin; +import jfxtras.scene.control.agenda.Agenda; + +import jfxtras.scene.control.agenda.Agenda.Appointment; +import seedu.address.commons.core.LogsCenter; +import seedu.address.model.calendarevent.CalendarEvent; + + +/** + * The Ui component that is responsible for displaying a List of CalendarEvents to the user + */ +public class CalendarDisplay extends UiPart { + private static final String FXML = "CalendarDisplay.fxml"; + private final Logger logger = LogsCenter.getLogger(CalendarDisplay.class); + + private ObservableList calendarEventList; + + private Agenda agenda; + + // keeps track of which week calendar is showing + private LocalDateTime currentDateTime = LocalDateTime.now() + .withHour(0).withMinute(0).withSecond(0).withNano(0); + + @FXML + private VBox calendarDisplayBox; + + public CalendarDisplay(ObservableList calendarEventList) { + super(FXML); + // registerAsAnEventHandler(this); // I don't think this is needed as of now + + this.calendarEventList = calendarEventList; + initAgenda(); // set up agenda internally + setConnections(calendarEventList); + setControls(); + } + + /** + * Starts up the internal Agenda Object + * Prevents the user from interacting directly with the calendar display + */ + private void initAgenda() { + agenda = new Agenda(); + + // register actionCallBack, to be executed when user double click on appointment + agenda.actionCallbackProperty().set(new Callback() { + @Override + public Void call(Appointment param) { + // can add more functionality here + logger.info("User double clicked on " + param.toString()); + return null; + } + }); + + // disable allowing user to create appointments by clicking on screen + agenda.setAppointmentChangedCallback(null); + + // disable dragging appointments around + agenda.setAllowDragging(false); + + // set the week for calendar to display + agenda.setDisplayedLocalDateTime(currentDateTime); + + // show 1 week + agenda.setSkin(new AgendaWeekSkin(agenda)); + + // add agenda to the VBox area + calendarDisplayBox.getChildren().add(agenda); + } + + /** + * Passes agenda the list of CalendarEvents to display + * @param calendarEventList + */ + private void setConnections(ObservableList calendarEventList) { + // populate the calendar by adding all the events to the calendar + agenda.appointments().addAll(calendarEventList); + + // TODO: fix weird add/remove all items bug for first command + this.calendarEventList.addListener(new ListChangeListener() { + @Override + public void onChanged(Change c) { + while (c.next()) { + if (c.wasRemoved()) { + for (CalendarEvent removedEvent : c.getRemoved()) { + agenda.appointments().remove(removedEvent); + System.out.println("REMOVED: " + removedEvent.getTitle()); + } + } + if (c.wasAdded()) { + for (CalendarEvent addedEvent : c.getAddedSubList()) { + agenda.appointments().add(addedEvent); + System.out.println("ADDED: " + addedEvent.getTitle()); + } + } + } + } + }); + } + + /** + * Temporary convienience method to test navigation + * The calendarDisplay must be in focus for this to work, i.e. must click on the calendar + * TODO: get help with the down key problem + */ + public void setControls() { + agenda.addEventFilter(KEY_PRESSED, new EventHandler() { + @Override + public void handle(KeyEvent event) { + if (event.getCode() == KeyCode.T) { // toggle between day and week view + logger.info("Toggle Pressed"); + if (agenda.getSkin() instanceof AgendaDaySkin) { + setViewToWeeklyView(); + } else if (agenda.getSkin() instanceof AgendaWeekSkin) { + setViewToDailyView(); + } + agenda.requestFocus(); + } else if (event.getCode() == KeyCode.LEFT) { + logger.info("LEFT arrow Pressed"); + if (agenda.getSkin() instanceof AgendaDaySkin) { + displayPreviousDay(); + } else if (agenda.getSkin() instanceof AgendaWeekSkin) { + displayPreviousWeek(); + } + } else if (event.getCode() == KeyCode.RIGHT) { + logger.info("RIGHT arrow Pressed"); + if (agenda.getSkin() instanceof AgendaDaySkin) { + displayNextDay(); + } else if (agenda.getSkin() instanceof AgendaWeekSkin) { + displayNextWeek(); + } + } + } + }); + } + + /** + * Toggle the view + */ + public void setViewToWeeklyView() { + agenda.setSkin(new AgendaWeekSkin(agenda)); // skin for viewing by week + } + + /** + * Toggle the view + */ + public void setViewToDailyView() { + agenda.setSkin(new AgendaDaySkin(agenda)); // skin for viewing by day + } + /** + * Navigation method + */ + public void displayNextWeek() { + currentDateTime = currentDateTime.plusDays(7); + agenda.setDisplayedLocalDateTime(currentDateTime); + } + + /** + * Navigation method + */ + public void displayPreviousWeek() { + currentDateTime = currentDateTime.minusDays(7); + agenda.setDisplayedLocalDateTime(currentDateTime); + } + + /** + * Navigation method + */ + public void displayNextDay() { + currentDateTime = currentDateTime.plusDays(1); + agenda.setDisplayedLocalDateTime(currentDateTime); + } + + /** + * Navigation method + */ + public void displayPreviousDay() { + currentDateTime = currentDateTime.minusDays(1); + agenda.setDisplayedLocalDateTime(currentDateTime); + } +} diff --git a/src/main/java/seedu/address/ui/CalendarEventCard.java b/src/main/java/seedu/address/ui/CalendarEventCard.java index 1f7b80b216f5..14eb91d4f0be 100644 --- a/src/main/java/seedu/address/ui/CalendarEventCard.java +++ b/src/main/java/seedu/address/ui/CalendarEventCard.java @@ -42,7 +42,7 @@ public CalendarEventCard(CalendarEvent calendarEvent, int displayedIndex) { this.calendarEvent = calendarEvent; id.setText(displayedIndex + ". "); title.setText(calendarEvent.getTitle().value); - description.setText(calendarEvent.getDescription().value); + description.setText(calendarEvent.getDescriptionObject().value); venue.setText(calendarEvent.getVenue().value); // TODO add start date and end date (remember to update fxml file) calendarEvent.getTags().forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 31443ba2a16b..c4609b66edc4 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -36,6 +36,7 @@ public class MainWindow extends UiPart { // Independent Ui parts residing in this Ui container private BrowserPanel browserPanel; + private CalendarDisplay calendarDisplay; private CalendarPanel calendarPanel; private Config config; private UserPrefs prefs; @@ -47,6 +48,9 @@ public class MainWindow extends UiPart { @FXML private StackPane resultDisplayPlaceholder; + @FXML + private StackPane calendarDisplayPlaceholder; + @FXML private StackPane commandBoxPlaceholder; @@ -127,6 +131,9 @@ void fillInnerParts() { TaskListPanel taskListPanel = new TaskListPanel(); taskListPanelPlaceholder.getChildren().add(taskListPanel.getRoot()); + calendarDisplay = new CalendarDisplay(logic.getFilteredCalendarEventList()); + calendarDisplayPlaceholder.getChildren().add(calendarDisplay.getRoot()); + DayMonthYearPanel dayMonthYearPanel = new DayMonthYearPanel(logic.getFilteredCalendarEventList()); dayMonthYearPanelPlaceholder.getChildren().add(dayMonthYearPanel.getRoot()); diff --git a/src/main/resources/view/CalendarDisplay.fxml b/src/main/resources/view/CalendarDisplay.fxml new file mode 100644 index 000000000000..e4b2dd3514f5 --- /dev/null +++ b/src/main/resources/view/CalendarDisplay.fxml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 90d349acd90f..64063b22d8fc 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -34,6 +34,11 @@ + + + + + getTags() { public boolean equals(CalendarEvent calendarEvent) { return getTitle().equals(calendarEvent.getTitle().value) && getVenue().equals(calendarEvent.getVenue().value) - && getDescription().equals(calendarEvent.getDescription().value) + && getDescription().equals(calendarEvent.getDescriptionObject().value) && ImmutableMultiset.copyOf(getTags()).equals(ImmutableMultiset.copyOf(calendarEvent.getTags().stream() .map(tag -> tag.tagName) .collect(Collectors.toList()))); diff --git a/src/test/java/seedu/address/storage/XmlAdaptedCalendarEventTest.java b/src/test/java/seedu/address/storage/XmlAdaptedCalendarEventTest.java index 8a13895f3af7..512c83e406fd 100644 --- a/src/test/java/seedu/address/storage/XmlAdaptedCalendarEventTest.java +++ b/src/test/java/seedu/address/storage/XmlAdaptedCalendarEventTest.java @@ -26,7 +26,7 @@ public class XmlAdaptedCalendarEventTest { private static final String INVALID_TAG = "#friend"; private static final String VALID_TITLE = BENSON.getTitle().toString(); - private static final String VALID_DESCRIPTION = BENSON.getDescription().toString(); + private static final String VALID_DESCRIPTION = BENSON.getDescriptionObject().toString(); private static final String VALID_START = BENSON.getStart().toInputFormat(); private static final String VALID_END = BENSON.getEnd().toInputFormat(); private static final String VALID_LOCATION = BENSON.getVenue().toString(); diff --git a/src/test/java/seedu/address/testutil/CalendarEventBuilder.java b/src/test/java/seedu/address/testutil/CalendarEventBuilder.java index 72f040a8ee3e..167d206c4c95 100644 --- a/src/test/java/seedu/address/testutil/CalendarEventBuilder.java +++ b/src/test/java/seedu/address/testutil/CalendarEventBuilder.java @@ -44,7 +44,7 @@ public CalendarEventBuilder() { */ public CalendarEventBuilder(CalendarEvent calendarEventToCopy) { title = calendarEventToCopy.getTitle(); - description = calendarEventToCopy.getDescription(); + description = calendarEventToCopy.getDescriptionObject(); start = calendarEventToCopy.getStart(); end = calendarEventToCopy.getEnd(); venue = calendarEventToCopy.getVenue(); diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java index c9e5cc8ef07a..d39ec477872e 100644 --- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java +++ b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java @@ -33,7 +33,7 @@ public EditPersonDescriptorBuilder(EditCalendarEventDescriptor descriptor) { public EditPersonDescriptorBuilder(CalendarEvent calendarEvent) { descriptor = new EditCalendarEventDescriptor(); descriptor.setTitle(calendarEvent.getTitle()); - descriptor.setDescription(calendarEvent.getDescription()); + descriptor.setDescription(calendarEvent.getDescriptionObject()); descriptor.setStart(calendarEvent.getStart()); descriptor.setEnd(calendarEvent.getEnd()); descriptor.setVenue(calendarEvent.getVenue()); diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java index daa78da813ef..97f7cc9f3ef5 100644 --- a/src/test/java/seedu/address/testutil/PersonUtil.java +++ b/src/test/java/seedu/address/testutil/PersonUtil.java @@ -32,7 +32,7 @@ public static String getAddCommand(CalendarEvent calendarEvent) { public static String getPersonDetails(CalendarEvent calendarEvent) { StringBuilder sb = new StringBuilder(); sb.append(PREFIX_TITLE + calendarEvent.getTitle().value + " "); - sb.append(PREFIX_DESCRIPTION + calendarEvent.getDescription().value + " "); + sb.append(PREFIX_DESCRIPTION + calendarEvent.getDescriptionObject().value + " "); sb.append(PREFIX_START + calendarEvent.getStart().toInputFormat() + " "); sb.append(PREFIX_END + calendarEvent.getEnd().toInputFormat() + " "); sb.append(PREFIX_VENUE + calendarEvent.getVenue().value + " "); diff --git a/src/test/java/seedu/address/ui/testutil/GuiTestAssert.java b/src/test/java/seedu/address/ui/testutil/GuiTestAssert.java index c2111aef7723..8dc64224e2cc 100644 --- a/src/test/java/seedu/address/ui/testutil/GuiTestAssert.java +++ b/src/test/java/seedu/address/ui/testutil/GuiTestAssert.java @@ -32,7 +32,7 @@ public static void assertCardEquals(CalendarEventCardHandle expectedCard, Calend public static void assertCardDisplaysPerson(CalendarEvent expectedCalendarEvent, CalendarEventCardHandle actualCard) { assertEquals(expectedCalendarEvent.getTitle().value, actualCard.getTitle()); - assertEquals(expectedCalendarEvent.getDescription().value, actualCard.getDescription()); + assertEquals(expectedCalendarEvent.getDescriptionObject().value, actualCard.getDescription()); assertEquals(expectedCalendarEvent.getVenue().value, actualCard.getVenue()); assertEquals(expectedCalendarEvent.getTags().stream().map(tag -> tag.tagName).collect(Collectors.toList()), actualCard.getTags()); diff --git a/src/test/java/systemtests/FindCommandSystemTest.java b/src/test/java/systemtests/FindCommandSystemTest.java index 2a993c709761..9ea424980990 100644 --- a/src/test/java/systemtests/FindCommandSystemTest.java +++ b/src/test/java/systemtests/FindCommandSystemTest.java @@ -117,7 +117,7 @@ public void find() { assertSelectedCardUnchanged(); /* Case: find phone number of calendarevent in address book -> 0 persons found */ - command = FindCommand.COMMAND_WORD + " " + DANIEL.getDescription().value; + command = FindCommand.COMMAND_WORD + " " + DANIEL.getDescriptionObject().value; assertCommandSuccess(command, expectedModel); assertSelectedCardUnchanged();