package org.noroomattheinn.visibletesla.dialogs; import org.noroomattheinn.fxextensions.VTDialog; import com.google.common.collect.Range; import java.util.Calendar; import java.util.List; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.stage.Stage; import javafx.util.Callback; import jfxtras.labs.scene.control.CalendarPicker; public class DateRangeDialog extends VTDialog.Controller { /*------------------------------------------------------------------------------ * * Internal State * *----------------------------------------------------------------------------*/ private Calendar start = null; private Calendar end = null; private boolean selectedAll = false; private Calendar highlightStart, highlightEnd; /*------------------------------------------------------------------------------ * * Internal State - UI Components * *----------------------------------------------------------------------------*/ @FXML private Button allButton; @FXML private Button cancelButton; @FXML private Button selectedButton; @FXML private CalendarPicker calendarPicker; @FXML private ComboBox<String> quickSelect; /*------------------------------------------------------------------------------ * * UI Initialization and Action Handlers * *----------------------------------------------------------------------------*/ @FXML void initialize() { quickSelect.valueProperty().addListener(handleQuickSelect); calendarPicker.setCalendarRangeCallback(new Callback<CalendarPicker.CalendarRange,java.lang.Void>() { @Override public Void call(CalendarPicker.CalendarRange p) { highlightDays(p.getStartCalendar()); return null; } }); } @FXML void buttonHandler(ActionEvent event) { Button b = (Button)event.getSource(); if (b == allButton) { selectedAll = true; } else if (b == selectedButton) { List<Calendar> selection = calendarPicker.calendars(); if (selection == null || selection.isEmpty()) { start = end = null; } else { start = selection.get(0); end = selection.get(selection.size()-1); } } else if (b == cancelButton) { start = end = null; } dialogStage.close(); } /*============================================================================== * ------- ------- * ------- Public Interface To This Class ------- * ------- ------- *============================================================================*/ public static DateRangeDialog show(Stage stage, Calendar sd, Calendar ed) { DateRangeDialog drd = VTDialog.<DateRangeDialog>load( DateRangeDialog.class.getResource("DateRangeDialog.fxml"), "Date Range for Export", stage); drd.setInitialValues(sd, ed); drd.show(); return drd; } public static Range<Long> getExportPeriod(Stage stage) { return getExportPeriod(stage, null, null); } public static Range<Long> getExportPeriod(Stage stage, Calendar sd, Calendar ed) { DateRangeDialog drd = DateRangeDialog.show(stage, sd, ed); if (drd.selectedAll()) { return Range.closed(0L, Long.MAX_VALUE); } Calendar start = drd.getStartCalendar(); Calendar end = drd.getEndCalendar(); if (start == null) { return null; } else { long t0 = start.getTimeInMillis(); long t1 = end.getTimeInMillis(); if (t1 < t0) return Range.closed(t1, t0); return Range.closed(t0, t1); } } public boolean selectedAll() { return selectedAll; } public Calendar getStartCalendar() { if (start == null) return null; return decodeDay(encodeDay(start), false); } public Calendar getEndCalendar() { if (end == null) return null; return decodeDay(encodeDay(end), true); } /*------------------------------------------------------------------------------ * * UI Action Handlers * *----------------------------------------------------------------------------*/ private final ChangeListener<String> handleQuickSelect = new ChangeListener<String>() { @Override public void changed( ObservableValue<? extends String> ov, String t, String t1) { Calendar now = Calendar.getInstance(); start = null; end = null; switch (t1) { case "Last 7 days": end = now; start = Calendar.getInstance(); start.add(Calendar.DAY_OF_YEAR, -6); break; case "Last 14 days": end = now; start = Calendar.getInstance(); start.add(Calendar.DAY_OF_YEAR, -13); break; case "Last 30 days": end = now; start = Calendar.getInstance(); start.add(Calendar.DAY_OF_YEAR, -29); break; case "This week": end = now; start = Calendar.getInstance(); start.set(Calendar.DAY_OF_WEEK, now.getActualMinimum(Calendar.DAY_OF_WEEK)); break; case "This month": end = now; start = Calendar.getInstance(); start.set(Calendar.DAY_OF_MONTH, now.getActualMinimum(Calendar.DAY_OF_MONTH)); break; case "None": default: break; } ObservableList<Calendar> calendars = calendarPicker.calendars(); calendars.clear(); if (start != null) { int startDay = encodeDay(start); int endDay = encodeDay(end); int curDay = startDay; while (curDay <= endDay) { Calendar c = decodeDay(curDay, curDay == endDay); calendars.add(c); Calendar next = (Calendar)c.clone(); next.add(Calendar.DAY_OF_YEAR, 1); curDay = encodeDay(next); } } } }; /*------------------------------------------------------------------------------ * * Private Utility methods * *----------------------------------------------------------------------------*/ private void setInitialValues(Calendar sd, Calendar ed) { if (sd != null) this.highlightStart = sd; if (ed != null) this.highlightEnd = ed; } private int encodeDay(Calendar day) { int encoded = day.get(Calendar.YEAR); encoded = (encoded * 1000) + day.get(Calendar.DAY_OF_YEAR); return encoded; } private Calendar decodeDay(int encoded, boolean endOfDay) { int year = encoded / 1000; int dayOfYear = encoded % 1000; Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, year); c.set(Calendar.DAY_OF_YEAR, dayOfYear); c.set(Calendar.HOUR_OF_DAY, endOfDay ? 23 : 0); c.set(Calendar.MINUTE, endOfDay ? 59 : 0); c.set(Calendar.SECOND, endOfDay ? 59 : 0); return c; } private Calendar beginningOfDay(Calendar day) { Calendar b = dupeCal(day); b.set(Calendar.HOUR_OF_DAY, 0); b.set(Calendar.MINUTE, 0); b.set(Calendar.SECOND, 1); return b; } private Calendar endOfDay(Calendar day) { Calendar e = dupeCal(day); e.set(Calendar.HOUR_OF_DAY, 23); e.set(Calendar.MINUTE, 59); e.set(Calendar.SECOND, 59); return e; } private Calendar lastDayOfMonth(Calendar day) { Calendar e = dupeCal(day); e.set(Calendar.DAY_OF_MONTH, 1); e.add(Calendar.MONTH, 1); e.add(Calendar.DAY_OF_MONTH, -1); return endOfDay(e); } private Calendar dupeCal(Calendar orig) { Calendar dupe = Calendar.getInstance(); dupe.setTimeInMillis(orig.getTimeInMillis()); return dupe; } private void highlightDays(Calendar month) { if (highlightStart == null || highlightEnd == null) return; calendarPicker.highlightedCalendars().clear(); Calendar cur = beginningOfDay(highlightStart); Calendar last = endOfDay(highlightEnd); Calendar lastOfMonth = lastDayOfMonth(month); while (cur.before(last) && cur.before(lastOfMonth)) { calendarPicker.highlightedCalendars().add(dupeCal(cur)); cur.add(Calendar.DAY_OF_YEAR, 1); } } }