package ru.khasang.cachoeira.viewcontroller.mainwindowcontrollers.propertiesmodules;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;
import javafx.event.ActionEvent;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import ru.khasang.cachoeira.commands.task.*;
import ru.khasang.cachoeira.model.ITask;
import ru.khasang.cachoeira.viewcontroller.MainWindowController;
import ru.khasang.cachoeira.view.mainwindow.properties.modules.IModule;
import ru.khasang.cachoeira.view.mainwindow.properties.modules.TaskInformation;
import java.time.LocalDate;
public class TaskInformationModuleController implements ModuleController {
private final TaskInformation module;
private final MainWindowController controller;
@SuppressWarnings("FieldCanBeLocal")
private ChangeListener<ITask> taskChangeListener;
@SuppressWarnings("FieldCanBeLocal")
private InvalidationListener nameFieldInvalidationListener;
@SuppressWarnings("FieldCanBeLocal")
private InvalidationListener costFieldInvalidationListener;
@SuppressWarnings("FieldCanBeLocal")
private InvalidationListener descriptionTextAreaInvalidationListener;
public TaskInformationModuleController(IModule module, MainWindowController controller) {
this.module = (TaskInformation) module;
this.controller = controller;
}
@Override
public void initModule() {
// set disable if selected task is null
module.disableProperty().bind(controller.selectedTaskProperty().isNull());
// init listeners
taskChangeListener = this::selectedTaskObserver;
nameFieldInvalidationListener = this::nameFieldUnfocused;
costFieldInvalidationListener = this::costFieldUnfocused;
descriptionTextAreaInvalidationListener = this::descriptionTextAreaUnfocused;
// set listener on selected task
controller.selectedTaskProperty().addListener(new WeakChangeListener<>(taskChangeListener));
// set handlers on fields events
module.getNameField().setOnKeyPressed(this::nameFieldHandler);
module.getStartDatePicker().setOnAction(this::startDatePickerHandler);
module.getFinishDatePicker().setOnAction(this::finishDatePickerHandler);
module.getDonePercentSlider().setOnMouseReleased(this::donePercentSliderHandler);
module.getCostField().setOnKeyPressed(this::costFieldHandler);
module.getDescriptionTextArea().setOnKeyPressed(this::descriptionTextAreaHandler);
// set listeners to discard changes when field is unfocused
module.getNameField().focusedProperty().addListener(new WeakInvalidationListener(nameFieldInvalidationListener));
module.getCostField().focusedProperty().addListener(new WeakInvalidationListener(costFieldInvalidationListener));
module.getDescriptionTextArea().focusedProperty().addListener(new WeakInvalidationListener(descriptionTextAreaInvalidationListener));
// set day cells disabled outer valid range
module.getStartDatePicker().setDayCellFactory(this::makeStartDatePickerCellsDisabled);
module.getFinishDatePicker().setDayCellFactory(this::makeFinishDatePickerCellsDisabled);
// set date enabled only by mouse
module.getStartDatePicker().setEditable(false);
module.getFinishDatePicker().setEditable(false);
}
private void nameFieldHandler(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
if (!module.getNameField().getText().trim().isEmpty()) {
controller.getCommandExecutor().execute(new RenameTaskCommand(
controller.getSelectedTask(),
module.getNameField().getText()));
module.getNameField().getParent().requestFocus();
}
}
if (event.getCode() == KeyCode.ESCAPE) {
module.getNameField().setText(controller.getSelectedTask().getName());
module.getNameField().getParent().requestFocus();
}
}
private void startDatePickerHandler(ActionEvent event) {
controller.getCommandExecutor().execute(new SetTaskStartDateCommand(
controller.getSelectedTask(),
module.getStartDatePicker().getValue()
));
}
private void finishDatePickerHandler(ActionEvent event) {
controller.getCommandExecutor().execute(new SetTaskFinishDateCommand(
controller.getSelectedTask(),
module.getFinishDatePicker().getValue()
));
}
private void donePercentSliderHandler(MouseEvent event) {
controller.getCommandExecutor().execute(new SetTaskDonePercentCommand(
controller.getSelectedTask(),
(int) module.getDonePercentSlider().getValue()
));
}
private void costFieldHandler(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
controller.getCommandExecutor().execute(new SetTaskCostCommand(
controller.getSelectedTask(),
Double.parseDouble(module.getCostField().getText())));
module.getDescriptionTextArea().getParent().requestFocus();
}
if (event.getCode() == KeyCode.ESCAPE) {
module.getCostField().setText(String.valueOf(controller.getSelectedTask().getCost()));
module.getCostField().getParent().requestFocus();
}
}
private void descriptionTextAreaHandler(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
controller.getCommandExecutor().execute(new SetTaskDescriptionCommand(
controller.getSelectedTask(),
module.getDescriptionTextArea().getText()));
module.getDescriptionTextArea().getParent().requestFocus();
}
if (event.getCode() == KeyCode.ESCAPE) {
module.getDescriptionTextArea().setText(controller.getSelectedTask().getDescription());
module.getDescriptionTextArea().getParent().requestFocus();
}
}
private void selectedTaskObserver(ObservableValue<? extends ITask> observableValue,
ITask oldTask,
ITask newTask) {
if (newTask != null) {
module.getNameField().setText(newTask.getName());
module.getStartDatePicker().setValue(newTask.getStartDate());
module.getFinishDatePicker().setValue(newTask.getFinishDate());
module.getDonePercentSlider().setValue(newTask.getDonePercent());
module.getCostField().setText(String.valueOf(newTask.getCost()));
module.getDescriptionTextArea().setText(newTask.getDescription());
}
}
private void nameFieldUnfocused(Observable observable) {
if (module.getNameField().isFocused()) {
module.getNameField().setText(controller.getSelectedTask().getName());
}
}
private void costFieldUnfocused(Observable observable) {
if (module.getCostField().isFocused()) {
module.getCostField().setText(String.valueOf(controller.getSelectedTask().getCost()));
}
}
private void descriptionTextAreaUnfocused(Observable observable) {
if (module.getDescriptionTextArea().isFocused()) {
module.getDescriptionTextArea().setText(controller.getSelectedTask().getDescription());
}
}
private DateCell makeStartDatePickerCellsDisabled(DatePicker datePicker) {
return new DateCell() {
@Override
public void updateItem(LocalDate startDate, boolean empty) {
super.updateItem(startDate, empty);
if (startDate.isBefore(controller.getProject().getStartDate())) {
setDisable(true);
}
if (startDate.isEqual(controller.getProject().getFinishDate()) || startDate.isAfter(controller.getProject().getFinishDate())) {
setDisable(true);
}
}
};
}
private DateCell makeFinishDatePickerCellsDisabled(DatePicker datePicker) {
return new DateCell() {
@Override
public void updateItem(LocalDate finishDate, boolean empty) {
super.updateItem(finishDate, empty);
if (finishDate.isBefore(module.getStartDatePicker().getValue().plusDays(1))) {
setDisable(true);
}
if (finishDate.isEqual(controller.getProject().getFinishDate().plusDays(1)) || finishDate.isAfter(controller.getProject().getFinishDate().plusDays(1))) {
setDisable(true);
}
}
};
}
}