Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.jfoenix.skins.JFXDatePickerContent Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.jfoenix.skins;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.WEEKS;
import static java.time.temporal.ChronoUnit.YEARS;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DecimalStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import com.jfoenix.assets.JFoenixResources;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDatePicker;
import com.jfoenix.controls.JFXListCell;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.svg.SVGGlyph;
import com.jfoenix.transitions.CachedTransition;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.ParallelTransition;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.DateCell;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.util.Duration;
/**
* @author Shadi Shaheen
*/
public class JFXDatePickerContent extends VBox
{
private static final String SPINNER_LABEL = "spinner-label";
private static final String ROBOTO = "Roboto";
private static final Color DEFAULT_CELL_COLOR = Color.valueOf("#9C9C9C");
private static final Color DEFAULT_COLOR = Color.valueOf("#313131");
private static final PseudoClass selectedYear = PseudoClass.getPseudoClass("selected-year");
protected JFXDatePicker datePicker;
private JFXButton backMonthButton;
private JFXButton forwardMonthButton;
private ObjectProperty selectedYearCell = new SimpleObjectProperty<>(null);
private Label selectedDateLabel;
private Label selectedYearLabel;
private Label monthYearLabel;
protected GridPane contentGrid;
private StackPane calendarPlaceHolder = new StackPane();
// animation
private CachedTransition showTransition;
private CachedTransition hideTransition;
private ParallelTransition tempImageTransition;
private int daysPerWeek = 7;
private List weekDaysCells = new ArrayList<>();
private List weekNumberCells = new ArrayList<>();
protected List dayCells = new ArrayList<>();
private LocalDate[] dayCellDates;
private DateCell currentFocusedDayCell = null;
private ListView yearsListView = new JFXListView()
{
{
this.getStyleClass().setAll("date-picker-list-view");
this.setCellFactory(listView -> new JFXListCell()
{
boolean mousePressed = false;
{
this.getStyleClass().setAll("data-picker-list-cell");
setOnMousePressed(click -> mousePressed = true);
setOnMouseReleased(release -> mousePressed = false);
setOnMouseClicked(click ->
{
String selectedItem = yearsListView.getSelectionModel().getSelectedItem();
if (selectedItem != null && selectedItem.equals(getText()))
{
int offset = Integer.parseInt(getText()) - Integer.parseInt(selectedYearLabel.getText());
forward(offset, YEARS, false, false);
hideTransition.setOnFinished(finish ->
{
selectedYearCell.set(this);
pseudoClassStateChanged(selectedYear, true);
setTextFill(datePicker.getDefaultColor());
yearsListView.scrollTo(this.getIndex() - 2 >= 0 ? this.getIndex() - 2 : this.getIndex());
hideTransition.setOnFinished(null);
});
hideTransition.play();
}
});
selectedYearLabel.textProperty().addListener((o, oldVal, newVal) ->
{
if (!yearsListView.isVisible() && newVal.equals(getText()))
{
selectedYearCell.set(this);
}
});
}
@Override
public void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (!empty)
{
final boolean isSelectedYear = item.equals(selectedYearLabel.getText());
if (isSelectedYear)
{
selectedYearCell.set(this);
}
pseudoClassStateChanged(selectedYear, isSelectedYear);
setTextFill(isSelectedYear ? datePicker.getDefaultColor() : DEFAULT_COLOR);
}
else
{
pseudoClassStateChanged(selectedYear, false);
setTextFill(DEFAULT_COLOR);
}
}
});
}
};
// Date formatters
final DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("MMMM");
final DateTimeFormatter yearFormatter = DateTimeFormatter.ofPattern("y");
final DateTimeFormatter weekNumberFormatter = DateTimeFormatter.ofPattern("w");
final DateTimeFormatter weekDayNameFormatter = DateTimeFormatter.ofPattern("ccc");
final DateTimeFormatter dayCellFormatter = DateTimeFormatter.ofPattern("d");
private ObjectProperty selectedYearMonth = new SimpleObjectProperty<>(this, "selectedYearMonth");
JFXDatePickerContent(final JFXDatePicker datePicker)
{
this.datePicker = datePicker;
getStyleClass().add("date-picker-popup");
LocalDate date = datePicker.getValue();
selectedYearMonth.set((date != null) ? YearMonth.from(date) : YearMonth.now());
selectedYearMonth.addListener((observable, oldValue, newValue) -> updateValues());
// add change listener to change the color of the selected year cell
selectedYearCell.addListener((o, oldVal, newVal) ->
{
if (oldVal != null)
{
oldVal.pseudoClassStateChanged(selectedYear, false);
oldVal.setTextFill(DEFAULT_COLOR);
}
if (newVal != null)
{
newVal.pseudoClassStateChanged(selectedYear, true);
newVal.setTextFill(datePicker.getDefaultColor());
}
});
// create the header pane
getChildren().add(createHeaderPane());
contentGrid = new GridPane()
{
@Override
protected double computePrefWidth(double height)
{
final int nCols = daysPerWeek + (datePicker.isShowWeekNumbers() ? 1 : 0);
final double leftSpace = snapSpace(getInsets().getLeft());
final double rightSpace = snapSpace(getInsets().getRight());
final double hgaps = snapSpace(getHgap()) * (nCols - 1);
// compute content width
final double contentWidth = super.computePrefWidth(height) - leftSpace - rightSpace - hgaps;
return ((snapSize(contentWidth / nCols)) * nCols) + leftSpace + rightSpace + hgaps;
}
@Override
protected void layoutChildren()
{
if (getWidth() > 0 && getHeight() > 0)
{
super.layoutChildren();
}
}
};
contentGrid.setFocusTraversable(true);
contentGrid.getStyleClass().add("calendar-grid");
contentGrid.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)));
contentGrid.setPadding(new Insets(0, 12, 12, 12));
contentGrid.setVgap(0);
contentGrid.setHgap(0);
// create week days cells
createWeekDaysCells();
// create month days cells
createDayCells();
VBox contentHolder = new VBox();
// create content pane
contentHolder.getChildren().setAll(createCalendarMonthLabelPane(), contentGrid);
// add month arrows pane
calendarPlaceHolder.getChildren().setAll(contentHolder, createCalendarArrowsPane());
Rectangle clip = new Rectangle();
clip.widthProperty().bind(calendarPlaceHolder.widthProperty());
clip.heightProperty().bind(calendarPlaceHolder.heightProperty());
calendarPlaceHolder.setClip(clip);
// create years list view
for (int i = 0; i <= 200; i++)
{
yearsListView.getItems().add(Integer.toString(1900 + i));
}
yearsListView.setVisible(false);
yearsListView.setOpacity(0);
yearsListView.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)));
StackPane contentPlaceHolder = new StackPane();
yearsListView.maxWidthProperty().bind(contentPlaceHolder.widthProperty());
yearsListView.maxHeightProperty().bind(contentPlaceHolder.heightProperty());
contentPlaceHolder.getChildren().setAll(calendarPlaceHolder, yearsListView);
getChildren().add(contentPlaceHolder);
refresh();
scrollToYear();
addEventHandler(KeyEvent.ANY, event ->
{
Node node = getScene().getFocusOwner();
if (node instanceof DateCell)
{
currentFocusedDayCell = (DateCell) node;
}
switch (event.getCode())
{
case HOME:
// go to the current date
init();
goToDate(LocalDate.now(), true);
event.consume();
break;
case PAGE_UP:
if (!backMonthButton.isDisabled())
{
forward(-1, MONTHS, true, true);
}
event.consume();
break;
case PAGE_DOWN:
if (!forwardMonthButton.isDisabled())
{
forward(1, MONTHS, true, true);
}
event.consume();
break;
case ESCAPE:
datePicker.hide();
event.consume();
break;
case F4:
case F10:
case UP:
case DOWN:
case LEFT:
case RIGHT:
case TAB:
break;
default:
event.consume();
}
});
// create animation
showTransition = new CachedTransition(yearsListView,
new Timeline(new KeyFrame(Duration.millis(0),
new KeyValue(yearsListView.opacityProperty(), 0, Interpolator.EASE_BOTH),
new KeyValue(calendarPlaceHolder.opacityProperty(), 1, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(500),
new KeyValue(yearsListView.opacityProperty(), 0, Interpolator.EASE_BOTH),
new KeyValue(calendarPlaceHolder.opacityProperty(), 0, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(1000),
new KeyValue(yearsListView.opacityProperty(), 1, Interpolator.EASE_BOTH),
new KeyValue(calendarPlaceHolder.opacityProperty(), 0, Interpolator.EASE_BOTH),
new KeyValue(selectedYearLabel.textFillProperty(), Color.WHITE, Interpolator.EASE_BOTH),
new KeyValue(selectedDateLabel.textFillProperty(),
Color.rgb(255, 255, 255, 0.67),
Interpolator.EASE_BOTH))))
{
{
setCycleDuration(Duration.millis(320));
setDelay(Duration.seconds(0));
}
@Override
protected void starting()
{
super.starting();
yearsListView.setVisible(true);
}
};
hideTransition = new CachedTransition(yearsListView,
new Timeline(new KeyFrame(Duration.millis(0),
new KeyValue(yearsListView.opacityProperty(), 1, Interpolator.EASE_BOTH),
new KeyValue(calendarPlaceHolder.opacityProperty(), 0, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(500),
new KeyValue(yearsListView.opacityProperty(), 0, Interpolator.EASE_BOTH),
new KeyValue(calendarPlaceHolder.opacityProperty(), 0, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.millis(1000),
new KeyValue(yearsListView.opacityProperty(), 0, Interpolator.EASE_BOTH),
new KeyValue(calendarPlaceHolder.opacityProperty(), 1, Interpolator.EASE_BOTH),
new KeyValue(selectedDateLabel.textFillProperty(), Color.WHITE, Interpolator.EASE_BOTH),
new KeyValue(selectedYearLabel.textFillProperty(),
Color.rgb(255, 255, 255, 0.67),
Interpolator.EASE_BOTH))))
{
{
setCycleDuration(Duration.millis(320));
setDelay(Duration.seconds(0));
}
@Override
protected void stopping()
{
super.stopping();
yearsListView.setVisible(false);
}
};
}
private final void scrollToYear()
{
int yearIndex = Integer.parseInt(selectedYearLabel.getText()) - 1900 - 2;
yearsListView.scrollTo(yearIndex >= 0 ? yearIndex : yearIndex + 2);
}
@Override
public String getUserAgentStylesheet()
{
return JFoenixResources.load("css/controls/jfx-date-picker.css").toExternalForm();
}
ObjectProperty displayedYearMonthProperty()
{
return selectedYearMonth;
}
private void createWeekDaysCells()
{
// create week days names
for (int i = 0; i < daysPerWeek; i++)
{
DateCell cell = new DateCell();
cell.getStyleClass().add("day-name-cell");
cell.setTextFill(DEFAULT_CELL_COLOR);
cell.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)));
cell.setFont(Font.font(ROBOTO, FontWeight.BOLD, 12));
cell.setAlignment(Pos.BASELINE_CENTER);
weekDaysCells.add(cell);
}
// create week days numbers
for (int i = 0; i < 6; i++)
{
DateCell cell = new DateCell();
cell.getStyleClass().add("week-number-cell");
cell.setTextFill(DEFAULT_CELL_COLOR);
cell.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)));
cell.setFont(Font.font(ROBOTO, FontWeight.BOLD, 12));
weekNumberCells.add(cell);
}
}
/*
* header panel represents the selected Date we keep javaFX original style classes
*/
protected VBox createHeaderPane()
{
// Year label
selectedYearLabel = new Label();
selectedYearLabel.getStyleClass().add(SPINNER_LABEL);
selectedYearLabel.setTextFill(Color.rgb(255, 255, 255, 0.67));
selectedYearLabel.setFont(Font.font(ROBOTO, FontWeight.BOLD, 14));
// Year label container
HBox yearLabelContainer = new HBox();
yearLabelContainer.getStyleClass().add("spinner");
yearLabelContainer.getChildren().addAll(selectedYearLabel);
yearLabelContainer.setAlignment(Pos.CENTER_LEFT);
yearLabelContainer.setFillHeight(false);
yearLabelContainer.setOnMouseClicked((click) ->
{
if (!yearsListView.isVisible())
{
scrollToYear();
hideTransition.stop();
showTransition.play();
}
});
// selected date label
selectedDateLabel = new Label();
selectedDateLabel.getStyleClass().add(SPINNER_LABEL);
selectedDateLabel.setTextFill(Color.WHITE);
selectedDateLabel.setFont(Font.font(ROBOTO, FontWeight.BOLD, 32));
// selected date label container
HBox selectedDateContainer = new HBox(selectedDateLabel);
selectedDateContainer.getStyleClass().add("spinner");
selectedDateContainer.setAlignment(Pos.CENTER_LEFT);
selectedDateContainer.setOnMouseClicked((click) ->
{
if (yearsListView.isVisible())
{
showTransition.stop();
hideTransition.play();
}
});
VBox headerPanel = new VBox();
headerPanel.getStyleClass().add("month-year-pane");
headerPanel.setBackground(new Background(new BackgroundFill(this.datePicker.getDefaultColor(), CornerRadii.EMPTY, Insets.EMPTY)));
headerPanel.setPadding(new Insets(12, 24, 12, 24));
headerPanel.getChildren().add(yearLabelContainer);
headerPanel.getChildren().add(selectedDateContainer);
return headerPanel;
}
/*
* methods to create the content of the date picker
*/
protected BorderPane createCalendarArrowsPane()
{
SVGGlyph leftChevron = new SVGGlyph(0,
"CHEVRON_LEFT",
"M 742,-37 90,614 Q 53,651 53,704.5 53,758 90,795 l 652,651 q 37,37 90.5,37 53.5,0 90.5,-37 l 75,-75 q 37,-37 37,-90.5 0,-53.5 -37,-90.5 L 512,704 998,219 q 37,-38 37,-91 0,-53 -37,-90 L 923,-37 Q 886,-74 832.5,-74 779,-74 742,-37 z",
Color.GRAY);
SVGGlyph rightChevron = new SVGGlyph(0,
"CHEVRON_RIGHT",
"m 1099,704 q 0,-52 -37,-91 L 410,-38 q -37,-37 -90,-37 -53,0 -90,37 l -76,75 q -37,39 -37,91 0,53 37,90 l 486,486 -486,485 q -37,39 -37,91 0,53 37,90 l 76,75 q 36,38 90,38 54,0 90,-38 l 652,-651 q 37,-37 37,-90 z",
Color.GRAY);
leftChevron.setFill(DEFAULT_COLOR);
leftChevron.setSize(6, 11);
rightChevron.setFill(DEFAULT_COLOR);
rightChevron.setSize(6, 11);
backMonthButton = new JFXButton();
backMonthButton.setMinSize(40, 40);
backMonthButton.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, new CornerRadii(40), Insets.EMPTY)));
backMonthButton.getStyleClass().add("left-button");
backMonthButton.setGraphic(leftChevron);
backMonthButton.setRipplerFill(this.datePicker.getDefaultColor());
backMonthButton.setOnAction(t -> forward(-1, MONTHS, false, true));
forwardMonthButton = new JFXButton();
forwardMonthButton.setMinSize(40, 40);
forwardMonthButton.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, new CornerRadii(40), Insets.EMPTY)));
forwardMonthButton.getStyleClass().add("right-button");
forwardMonthButton.setGraphic(rightChevron);
forwardMonthButton.setRipplerFill(this.datePicker.getDefaultColor());
forwardMonthButton.setOnAction(t -> forward(1, MONTHS, false, true));
BorderPane arrowsContainer = new BorderPane();
arrowsContainer.setLeft(backMonthButton);
arrowsContainer.setRight(forwardMonthButton);
arrowsContainer.setPadding(new Insets(4, 12, 2, 12));
arrowsContainer.setPickOnBounds(false);
return arrowsContainer;
}
protected BorderPane createCalendarMonthLabelPane()
{
monthYearLabel = new Label();
monthYearLabel.getStyleClass().add(SPINNER_LABEL);
monthYearLabel.setFont(Font.font(ROBOTO, FontWeight.BOLD, 13));
monthYearLabel.setTextFill(DEFAULT_COLOR);
BorderPane monthContainer = new BorderPane();
monthContainer.setMinHeight(50);
monthContainer.setCenter(monthYearLabel);
monthContainer.setPadding(new Insets(2, 12, 2, 12));
return monthContainer;
}
void updateContentGrid()
{
contentGrid.getColumnConstraints().clear();
contentGrid.getChildren().clear();
int colsNumber = daysPerWeek + (datePicker.isShowWeekNumbers() ? 1 : 0);
ColumnConstraints columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(100);
for (int i = 0; i < colsNumber; i++)
{
contentGrid.getColumnConstraints().add(columnConstraints);
}
// Week days cells
for (int i = 0; i < daysPerWeek; i++)
{
contentGrid.add(weekDaysCells.get(i), i + colsNumber - daysPerWeek, 1);
}
// Week number cells
if (datePicker.isShowWeekNumbers())
{
for (int i = 0; i < 6; i++)
{
contentGrid.add(weekNumberCells.get(i), 0, i + 2);
}
}
// Month days cells
for (int row = 0; row < 6; row++)
{
for (int col = 0; col < daysPerWeek; col++)
{
contentGrid.add(dayCells.get(row * daysPerWeek + col), col + colsNumber - daysPerWeek, row + 2);
}
}
}
private void refresh()
{
updateDayNameCells();
updateValues();
}
private void updateDayNameCells()
{
int weekFirstDay = WeekFields.of(getLocale()).getFirstDayOfWeek().getValue();
LocalDate date = LocalDate.of(2009, 7, 12 + weekFirstDay);
for (int i = 0; i < daysPerWeek; i++)
{
String name = weekDayNameFormatter.withLocale(getLocale()).format(date.plus(i, DAYS));
// Fix Chinese environment week display incorrectly
// Take the last character of the Chinese weekday names
if (weekDayNameFormatter.getLocale() == java.util.Locale.CHINA)
{
name = name.substring(name.length() - 1).toUpperCase();
}
else
{
name = name.substring(0, 1).toUpperCase();
}
weekDaysCells.get(i).setText(name);
}
}
void updateValues()
{
updateWeekNumberDateCells();
updateDayCells();
updateMonthYearPane();
}
void updateWeekNumberDateCells()
{
if (datePicker.isShowWeekNumbers())
{
final Locale locale = getLocale();
LocalDate firstDayOfMonth = selectedYearMonth.get().atDay(1);
for (int i = 0; i < 6; i++)
{
LocalDate date = firstDayOfMonth.plus(i, WEEKS);
String weekNumber = weekNumberFormatter.withLocale(locale).withDecimalStyle(DecimalStyle.of(locale)).format(date);
weekNumberCells.get(i).setText(weekNumber);
}
}
}
private void updateDayCells()
{
Locale locale = getLocale();
Chronology chrono = getPrimaryChronology();
// get the index of the first day of the month
int firstDayOfWeek = WeekFields.of(getLocale()).getFirstDayOfWeek().getValue();
int firstOfMonthIndex = selectedYearMonth.get().atDay(1).getDayOfWeek().getValue() - firstDayOfWeek;
firstOfMonthIndex += firstOfMonthIndex < 0 ? daysPerWeek : 0;
YearMonth currentYearMonth = selectedYearMonth.get();
int daysInCurMonth = -1;
for (int i = 0; i < 6 * daysPerWeek; i++)
{
DateCell dayCell = dayCells.get(i);
dayCell.getStyleClass().setAll("cell", "date-cell", "day-cell");
dayCell.setPrefSize(40, 42);
dayCell.setDisable(false);
dayCell.setStyle(null);
dayCell.setGraphic(null);
dayCell.setTooltip(null);
dayCell.setTextFill(DEFAULT_COLOR);
dayCell.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)));
try
{
if (daysInCurMonth == -1)
{
daysInCurMonth = currentYearMonth.lengthOfMonth();
}
int dayIndex = i - firstOfMonthIndex + 1;
LocalDate date = currentYearMonth.atDay(dayIndex);
dayCellDates[i] = date;
// if it's today
if (date.equals(LocalDate.now()))
{
dayCell.setTextFill(this.datePicker.getDefaultColor());
dayCell.getStyleClass().add("today");
}
// if it's the current selected value
if (date.equals(datePicker.getValue()))
{
dayCell.getStyleClass().add("selected");
dayCell.setTextFill(Color.WHITE);
dayCell.setBackground(new Background(new BackgroundFill(this.datePicker.getDefaultColor(), new CornerRadii(40), Insets.EMPTY)));
}
ChronoLocalDate cDate = chrono.date(date);
String cellText = dayCellFormatter.withLocale(locale).withChronology(chrono).withDecimalStyle(DecimalStyle.of(locale)).format(cDate);
dayCell.setText(cellText);
if (i < firstOfMonthIndex)
{
dayCell.getStyleClass().add("previous-month");
dayCell.setText("");
}
else if (i >= firstOfMonthIndex + daysInCurMonth)
{
dayCell.getStyleClass().add("next-month");
dayCell.setText("");
}
// update cell item
dayCell.updateItem(date, false);
}
catch (DateTimeException ex)
{
// Disable day cell if its date is out of range
dayCell.setText("");
dayCell.setDisable(true);
}
}
}
protected void updateMonthYearPane()
{
// update date labels
YearMonth yearMonth = selectedYearMonth.get();
LocalDate value = datePicker.getValue();
value = value == null ? LocalDate.now() : value;
selectedDateLabel.setText(DateTimeFormatter.ofPattern("EEE, MMM dd").format(value));
selectedYearLabel.setText(formatYear(yearMonth));
monthYearLabel.setText(formatMonth(yearMonth) + " " + formatYear(yearMonth));
Chronology chrono = datePicker.getChronology();
LocalDate firstDayOfMonth = yearMonth.atDay(1);
backMonthButton.setDisable(!isValidDate(chrono, firstDayOfMonth, -1, DAYS));
forwardMonthButton.setDisable(!isValidDate(chrono, firstDayOfMonth, +1, MONTHS));
}
private String formatMonth(YearMonth yearMonth)
{
try
{
Chronology chrono = getPrimaryChronology();
ChronoLocalDate cDate = chrono.date(yearMonth.atDay(1));
return monthFormatter.withLocale(getLocale()).withChronology(chrono).format(cDate);
}
catch (DateTimeException ex)
{
// Date is out of range.
return "";
}
}
private String formatYear(YearMonth yearMonth)
{
try
{
Chronology chrono = getPrimaryChronology();
ChronoLocalDate cDate = chrono.date(yearMonth.atDay(1));
return yearFormatter.withLocale(getLocale()).withChronology(chrono).withDecimalStyle(DecimalStyle.of(getLocale())).format(cDate);
}
catch (DateTimeException ex)
{
// Date is out of range.
return "";
}
}
protected LocalDate dayCellDate(DateCell dateCell)
{
assert dayCellDates != null;
return dayCellDates[dayCells.indexOf(dateCell)];
}
protected void forward(int offset, ChronoUnit unit, boolean focusDayCell, boolean withAnimation)
{
if (withAnimation)
{
if (tempImageTransition == null || tempImageTransition.getStatus() == Status.STOPPED)
{
Pane monthContent = (Pane) calendarPlaceHolder.getChildren().get(0);
this.getParent().setManaged(false);
SnapshotParameters snapShotparams = new SnapshotParameters();
snapShotparams.setFill(Color.TRANSPARENT);
WritableImage temp = monthContent.snapshot(snapShotparams, new WritableImage((int) monthContent.getWidth(), (int) monthContent.getHeight()));
ImageView tempImage = new ImageView(temp);
calendarPlaceHolder.getChildren().add(calendarPlaceHolder.getChildren().size() - 2, tempImage);
TranslateTransition imageTransition = new TranslateTransition(Duration.millis(160), tempImage);
imageTransition.setToX(-offset * calendarPlaceHolder.getWidth());
imageTransition.setOnFinished((finish) -> calendarPlaceHolder.getChildren().remove(tempImage));
monthContent.setTranslateX(offset * calendarPlaceHolder.getWidth());
TranslateTransition contentTransition = new TranslateTransition(Duration.millis(160), monthContent);
contentTransition.setToX(0);
tempImageTransition = new ParallelTransition(imageTransition, contentTransition);
tempImageTransition.setOnFinished((finish) ->
{
calendarPlaceHolder.getChildren().remove(tempImage);
this.getParent().setManaged(true);
});
tempImageTransition.play();
}
}
YearMonth yearMonth = selectedYearMonth.get();
DateCell dateCell = currentFocusedDayCell;
if (dateCell == null || !(dayCellDate(dateCell).getMonth() == yearMonth.getMonth()))
{
dateCell = findDayCellOfDate(yearMonth.atDay(1));
}
goToDayCell(dateCell, offset, unit, focusDayCell);
}
private void goToDayCell(DateCell dateCell, int offset, ChronoUnit unit, boolean focusDayCell)
{
YearMonth yearMonth = selectedYearMonth.get().plus(offset, unit);
goToDate(dayCellDate(dateCell).plus(offset, unit).withYear(yearMonth.getYear()), focusDayCell);
}
private void goToDate(LocalDate date, boolean focusDayCell)
{
if (isValidDate(datePicker.getChronology(), date))
{
selectedYearMonth.set(YearMonth.from(date));
if (focusDayCell)
{
findDayCellOfDate(date).requestFocus();
}
}
}
private void selectDayCell(DateCell dateCell)
{
datePicker.setValue(dayCellDate(dateCell));
datePicker.hide();
}
private DateCell findDayCellOfDate(LocalDate date)
{
for (int i = 0; i < dayCellDates.length; i++)
{
if (date.equals(dayCellDates[i]))
{
return dayCells.get(i);
}
}
return dayCells.get(dayCells.size() / 2 + 1);
}
void init()
{
calendarPlaceHolder.setOpacity(1);
selectedDateLabel.setTextFill(Color.WHITE);
selectedYearLabel.setTextFill(Color.rgb(255, 255, 255, 0.67));
yearsListView.setOpacity(0);
yearsListView.setVisible(false);
}
void clearFocus()
{
LocalDate focusDate = datePicker.getValue();
if (focusDate == null)
{
focusDate = LocalDate.now();
}
if (YearMonth.from(focusDate).equals(selectedYearMonth.get()))
{
goToDate(focusDate, true);
}
}
protected void createDayCells()
{
for (int row = 0; row < 6; row++)
{
for (int col = 0; col < daysPerWeek; col++)
{
DateCell dayCell = createDayCell();
dayCell.addEventHandler(MouseEvent.MOUSE_CLICKED, click ->
{
// allow date selection on mouse primary button click
if (click.getButton() != MouseButton.PRIMARY)
{
return;
}
DateCell selectedDayCell = (DateCell) click.getSource();
selectDayCell(selectedDayCell);
currentFocusedDayCell = selectedDayCell;
});
// add mouse hover listener
dayCell.setOnMouseEntered((event) ->
{
if (!dayCell.getStyleClass().contains("selected"))
{
dayCell.setBackground(new Background(new BackgroundFill(Color.valueOf("#EDEDED"), new CornerRadii(40), Insets.EMPTY)));
}
});
dayCell.setOnMouseExited((event) ->
{
if (!dayCell.getStyleClass().contains("selected"))
{
dayCell.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
dayCell.setAlignment(Pos.BASELINE_CENTER);
dayCell.setBorder(new Border(new BorderStroke(Color.TRANSPARENT, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(5))));
dayCell.setFont(Font.font(ROBOTO, FontWeight.BOLD, 12));
dayCells.add(dayCell);
}
}
dayCellDates = new LocalDate[6 * daysPerWeek];
// position the cells into the grid
updateContentGrid();
}
private DateCell createDayCell()
{
DateCell dayCell = null;
// call cell factory if set by the user
if (datePicker.getDayCellFactory() != null)
{
dayCell = datePicker.getDayCellFactory().call(datePicker);
}
// else create the defaul day cell
if (dayCell == null)
{
dayCell = new DateCell();
}
return dayCell;
}
/**
* this method must be overriden when implementing other Chronolgy
*/
protected Chronology getPrimaryChronology()
{
return datePicker.getChronology();
}
protected Locale getLocale()
{
// for android compatibility
return Locale.getDefault(/* Locale.Category.FORMAT */);
}
protected boolean isValidDate(Chronology chrono, LocalDate date, int offset, ChronoUnit unit)
{
return date != null && isValidDate(chrono, date.plus(offset, unit));
}
protected boolean isValidDate(Chronology chrono, LocalDate date)
{
try
{
if (date != null)
{
chrono.date(date);
}
return true;
}
catch (DateTimeException ex)
{
return false;
}
}
}