/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/>
* -----------------------------------------------------------------------
* This file (YearView.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see <http://www.gnu.org/licenses/>.
* -----------------------------------------------------------------------
*/
package net.time4j.ui.javafx;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import net.time4j.PlainDate;
import net.time4j.engine.CalendarDate;
import net.time4j.engine.CalendarVariant;
import net.time4j.engine.EpochDays;
import net.time4j.format.DisplayMode;
import net.time4j.format.expert.ChronoFormatter;
import net.time4j.format.expert.PatternType;
import net.time4j.range.CalendarYear;
import net.time4j.range.DateInterval;
import java.util.Locale;
class YearView<T extends CalendarDate>
extends TableView<T> {
//~ Statische Felder/Initialisierungen --------------------------------
private static final String CSS_CALENDAR_YEAR_VIEW = "calendar-year-view";
private static final String CSS_CALENDAR_CELL_INSIDE_RANGE = "calendar-cell-inside-range";
private static final int NUM_OF_COLUMNS = 3;
//~ Konstruktoren -----------------------------------------------------
protected YearView(
CalendarControl<T> control,
FXCalendarSystem<T> calsys,
boolean animationMode
) {
super(control, calsys, animationMode);
getStyleClass().add(CSS_CALENDAR_YEAR_VIEW);
if (!this.isAnimationMode()) {
// listen to arrow keys
this.setEventHandler(
KeyEvent.KEY_PRESSED,
event -> {
KeyCode code = event.getCode();
if (code.isArrowKey()) {
int index = -1;
for (int i = 0, n = getChildren().size(); i < n; i++) {
Node cell = getChildren().get(i);
if (cell.isFocused()) {
index = i;
break;
}
}
if (index != -1) {
int rowIndex = index / NUM_OF_COLUMNS;
int colIndex = index % NUM_OF_COLUMNS;
switch (code) {
case UP:
rowIndex = Math.max(0, rowIndex - 1);
break;
case RIGHT:
colIndex = Math.min(NUM_OF_COLUMNS - 1, colIndex + 1);
break;
case DOWN:
rowIndex = Math.min((getChildren().size() - 1) / NUM_OF_COLUMNS, rowIndex + 1);
break;
case LEFT:
colIndex = Math.max(0, colIndex - 1);
break;
default:
return;
}
int newIndex = Math.min(getChildren().size() - 1, rowIndex * NUM_OF_COLUMNS + colIndex);
Node cell = getChildren().get(newIndex);
if (!cell.isDisabled()) {
cell.requestFocus();
}
}
event.consume();
}
}
);
}
}
//~ Methoden ----------------------------------------------------------
@Override
protected void buildContent() {
for (int i = 0, n = this.getCalendarSystem().getCountOfMonths(); i < n; i++) {
Button button = new Button();
button.getStyleClass().add(CSS_CALENDAR_CELL_INSIDE_RANGE);
button.setMaxWidth(Double.MAX_VALUE);
button.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(button, Priority.ALWAYS);
GridPane.setHgrow(button, Priority.ALWAYS);
button.setOnAction(
actionEvent -> {
if (getControl().viewIndexProperty().get() == NavigationBar.YEAR_VIEW) {
T clickedDate = getControl().chronology().getChronoType().cast(button.getUserData());
getControl().pageDateProperty().setValue(clickedDate);
getControl().viewIndexProperty().set(NavigationBar.MONTH_VIEW);
}
}
);
int colIndex = i % NUM_OF_COLUMNS;
int rowIndex = i / NUM_OF_COLUMNS;
add(button, colIndex, rowIndex);
}
}
@Override
protected void updateContent(T date) {
Locale locale = this.getControl().localeProperty().get();
if (locale == null) {
locale = Locale.ROOT;
}
T min = null;
T max = null;
for (int i = 0, n = this.getCalendarSystem().getCountOfMonths(); i < n; i++) {
Button button = (Button) getChildren().get(i);
try {
T btnDate = this.getCalendarSystem().withMonth(date, i + 1);
if (min == null) {
min = btnDate;
} else {
max = btnDate;
}
if (
getCalendarSystem().withLastDayOfMonth(btnDate).isBefore(getControl().minDateProperty().get())
|| getCalendarSystem().withFirstDayOfMonth(btnDate).isAfter(getControl().maxDateProperty().get())
) {
button.setDisable(true);
button.setText(" ");
button.setUserData(null);
} else {
button.setDisable(false);
int month = this.getCalendarSystem().getMonth(btnDate);
button.setText(this.getCalendarSystem().formatMonth(month, locale));
button.setUserData(btnDate);
}
} catch (ArithmeticException | IllegalArgumentException ex) {
button.setDisable(true);
button.setText(" ");
button.setUserData(null);
}
}
if (!this.isAnimationMode()) {
String pattern = CalendarYear.chronology().getFormatPattern(DisplayMode.FULL, locale);
if (!(date instanceof PlainDate)) {
if (this.getControl().chronology().getFormatPattern(DisplayMode.MEDIUM, locale).endsWith("G")) {
pattern = pattern + " G";
} else {
pattern = "G " + pattern;
}
}
this.titleProperty().setValue(
ChronoFormatter.ofPattern(pattern, PatternType.CLDR, locale, getControl().chronology()).format(date)
);
min = this.getCalendarSystem().withFirstDayOfMonth(min);
max = this.getCalendarSystem().withLastDayOfMonth(max);
DateInterval range =
DateInterval.between(
PlainDate.of(min.getDaysSinceEpochUTC(), EpochDays.UTC),
PlainDate.of(max.getDaysSinceEpochUTC(), EpochDays.UTC)
);
String prefix;
if (min instanceof CalendarVariant) {
prefix = CalendarVariant.class.cast(min).getVariant();
} else {
prefix = getCalendarSystem().getCalendarType();
}
this.infoProperty().setValue(prefix + ": " + range.toString());
}
}
@Override
protected int getViewIndex() {
return NavigationBar.YEAR_VIEW;
}
}