package ru.khasang.cachoeira.view.mainwindow.diagram.ganttplan.dateline; import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.control.OverrunStyle; import javafx.scene.layout.HBox; import ru.khasang.cachoeira.viewcontroller.MainWindowController; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.Locale; public abstract class DateLine extends HBox{ protected MainWindowController controller; @SuppressWarnings("FieldCanBeLocal") private InvalidationListener listener; // Если листенер объявить локально, то GC прибьет его раньше времени public DateLine() { setAlignment(Pos.CENTER_LEFT); // Высота строки с датами setMaxHeight(24); setMinHeight(24); } /** * Метод для инициализации строки с датами * * @param projectStartDate Начальная дата проекта * @param projectFinishDate Конечная дата проекта * @param zoomValue Ширина одного дня в пикселях */ public void initDateLine(LocalDate projectStartDate, LocalDate projectFinishDate, int zoomValue) { if (zoomValue <= 130 && zoomValue >= 101) { String pattern = "dd MMMM yy"; createDateLine(projectStartDate, projectFinishDate, 1, pattern); } else if (zoomValue <= 100 && zoomValue >= 70) { String pattern = "dd.MM.yyyy"; createDateLine(projectStartDate, projectFinishDate, 1, pattern); } else if (zoomValue <= 69 && zoomValue >= 55) { String pattern = "dd.MM.yy"; createDateLine(projectStartDate, projectFinishDate, 1, pattern); } else if (zoomValue <= 54 && zoomValue >= 40) { String pattern1 = "dd"; String pattern2 = "dd.MM.yy"; createDateLine(projectStartDate, projectFinishDate, 2, pattern1, pattern2); } else if (zoomValue <= 39 && zoomValue >= 20) { String pattern1 = "dd"; String pattern2 = "dd.MM.yy"; createDateLine(projectStartDate, projectFinishDate, 4, pattern1, pattern2); } else if (zoomValue <= 19 && zoomValue >= 8) { String pattern = "dd.MM.yy"; createDateLine(projectStartDate, projectFinishDate, 7, pattern); } else if (zoomValue <= 7 && zoomValue >= 4) { String pattern = "dd.MM.yy"; createDateLine(projectStartDate, projectFinishDate, 14, pattern); } else if (zoomValue <= 3 && zoomValue >= 2) { String pattern = "dd.MM.yy"; createDateLine(projectStartDate, projectFinishDate, 28, pattern); } } /** * Метод создающий строку с датами с заданными прамаметрами * * @param projectStartDate Начальная дата проекта * @param projectFinishDate Конечная дата проекта * @param multiplier Множитель * @param pattern Паттерны для DateTimeFormatter (к примеру dd.MM.yyyy), * можно передать два паттерна для вида dd - dd.MM.yy. */ private void createDateLine(LocalDate projectStartDate, LocalDate projectFinishDate, int multiplier, String... pattern) { long between = ChronoUnit.DAYS.between(projectStartDate, projectFinishDate); //находим разницу между начальной и конечной датой проекта this.getChildren().clear(); for (int i = 0; i < between; i = i + multiplier) { String dateFormatter; if (pattern.length == 1) { // Если передан только один паттерн, то... dateFormatter = DateTimeFormatter.ofPattern(pattern[0], Locale.getDefault()).format(projectStartDate.plusDays(i)); } else { // ...если два, то... String df1 = DateTimeFormatter.ofPattern(pattern[0], Locale.getDefault()).format(projectStartDate.plusDays(i)); String df2 = DateTimeFormatter.ofPattern(pattern[1], Locale.getDefault()).format(projectStartDate.plusDays(i + (multiplier - 1))); dateFormatter = df1 + " - " + df2; } Label dateLabel = createDateLabel(multiplier, dateFormatter); this.getChildren().add(dateLabel); } } /** * Этот метод создает лейбл с заданными параметрами * * @param multiplier Множитель для ширины "столбца" * @param dateFormatter Формат даты * @return Лейбл **/ private Label createDateLabel(int multiplier, String dateFormatter) { Label dateLabel = new Label(dateFormatter); //фигачим лейбл с датой на борту dateLabel.setTextOverrun(OverrunStyle.CLIP); dateLabel.setPrefWidth(controller.getZoomMultiplier() * multiplier); dateLabel.setMinHeight(24); dateLabel.getStylesheets().add(this.getClass().getResource("/css/header.css").toExternalForm()); // делаем красиво dateLabel.setAlignment(Pos.CENTER); return dateLabel; } /** * Метод в котором определяются "слушатели" на заданные параметры, * при изменении которых происходит перерисовка строки с датами и диаграммы. * * @param projectStartDateProperty Проперти начальной даты проекта * @param projectFinishDateProperty Проперти конечной даты проекта * @param zoomMultiplierProperty Проперти множителя */ public void setListeners(ObjectProperty<LocalDate> projectStartDateProperty, ObjectProperty<LocalDate> projectFinishDateProperty, IntegerProperty zoomMultiplierProperty) { listener = observable -> refreshDateLine( projectStartDateProperty.getValue(), projectFinishDateProperty.getValue(), zoomMultiplierProperty.getValue()); projectStartDateProperty.addListener(new WeakInvalidationListener(listener)); projectFinishDateProperty.addListener(new WeakInvalidationListener(listener)); zoomMultiplierProperty.addListener(new WeakInvalidationListener(listener)); } /** * Метод для обновления строки с датами. * * @param projectStartDate Начальная дата проекта * @param projectFinishDate Конечная дата проекта * @param zoomMultiplier Множитель */ private void refreshDateLine(LocalDate projectStartDate, LocalDate projectFinishDate, int zoomMultiplier) { initDateLine(projectStartDate, projectFinishDate, zoomMultiplier); } }