All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jfxtras.internal.scene.control.skin.agenda.icalendar.base24hour.popup.EditDescriptiveLocatableVBox Maven / Gradle / Ivy

The newest version!
package jfxtras.internal.scene.control.skin.agenda.icalendar.base24hour.popup;

import java.time.DateTimeException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.util.List;
import java.util.Locale;

import javafx.beans.value.ChangeListener;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import jfxtras.icalendarfx.components.VLocatable;
import jfxtras.scene.control.LocalDateTextField;
import jfxtras.scene.control.LocalDateTimeTextField;
import jfxtras.scene.control.agenda.TemporalUtilities;

/**
 * Added dateTimeEnd or dateTimeDue to {@link EditDescriptiveVBox}
 * 
 * @author David Bal
 *
 * @param  subclass of {@link VComponentLocatable}
 */
public abstract class EditDescriptiveLocatableVBox> extends EditDescriptiveVBox
{
    private static final Duration DEFAULT_DURATION = Duration.ofHours(1);
    protected LocalDateTimeTextField endDateTimeTextField = new LocalDateTimeTextField(); // end of recurrence
    protected LocalDateTextField endDateTextField = new LocalDateTextField(); // end of recurrence when wholeDayCheckBox is selected
    
    public EditDescriptiveLocatableVBox()
    {
        super();
        endDateTimeTextField.setId("endDateTimeTextField");
        endDateTextField.setId("endDateTextField");
    }
    
    @Override
    void synchStartDateTime(LocalDateTime oldValue, LocalDateTime newValue)
    {
        super.synchStartDateTime(oldValue, newValue);
        LocalDateTime end = endDateTimeTextField.getLocalDateTime();
        if ((oldValue != null) && (end != null))
        {
            TemporalAmount duration = Duration.between(oldValue, end);
            endDateTimeTextField.setLocalDateTime(newValue.plus(duration));
        }
    }
    
    @Override
    void synchStartDate(LocalDate oldValue, LocalDate newValue)
    {
        super.synchStartDate(oldValue, newValue);
        LocalDate end = endDateTextField.getLocalDate();
        if ((oldValue != null) && (end != null))
        {
            TemporalAmount duration = Period.between(oldValue, end);
            endDateTextField.setLocalDate(newValue.plus(duration));
        }
    }
    
    final private ChangeListener endDateTextListener = (observable, oldValue, newValue) -> synchEndDate(oldValue, newValue);

    /** Update endDateTimeTextField when endDateTextField changes */
    void synchEndDate(LocalDate oldValue, LocalDate newValue)
    {
        endNewRecurrence = newValue;
        endDateTimeTextField.localDateTimeProperty().removeListener(endDateTimeTextListener);
        LocalDateTime newDateTime = endDateTimeTextField.getLocalDateTime().with(newValue.minusDays(1));
        endDateTimeTextField.setLocalDateTime(newDateTime);
        endDateTimeTextField.localDateTimeProperty().addListener(endDateTimeTextListener);
    }

    final private ChangeListener endDateTimeTextListener = (observable, oldValue, newValue) -> synchEndDateTime(oldValue, newValue);

    /** Update endDateTextField when endDateTimeTextField changes */
    void synchEndDateTime(LocalDateTime oldValue, LocalDateTime newValue)
    {
        if (startOriginalRecurrence.isSupported(ChronoUnit.NANOS)) // ZoneDateTime, LocalDateTime
        {
            endNewRecurrence = startOriginalRecurrence.with(newValue);            
        } else // LocalDate - use ZonedDateTime at system default ZoneId
        {
            endNewRecurrence = ZonedDateTime.of(newValue, ZoneId.systemDefault());
        }
        endDateTextField.localDateProperty().removeListener(endDateTextListener);
        LocalDate newDate = LocalDate.from(endDateTimeTextField.getLocalDateTime()).plusDays(1);
        endDateTextField.setLocalDate(newDate);
        endDateTextField.localDateProperty().addListener(endDateTextListener);
    }

    Temporal endNewRecurrence; // bound to endTextField, but adjusted to be DateTimeType identical to VComponent DTSTART, updated in endTextListener

    @Override
    public void setupData(
            T vComponent,
            Temporal startRecurrence,
            Temporal endRecurrence,
            List categories)
    {
        // String bindings
        String initialDescription = (vComponent.getDescription() == null || vComponent.getDescription().getValue() == null) ? "" : vComponent.getDescription().getValue();
		descriptionTextArea.setText(initialDescription);
        descriptionTextArea.textProperty().addListener((obs, oldValue, newValue) -> vComponent.setDescription(newValue));

        String initialLocation = (vComponent.getLocation() == null || vComponent.getLocation().getValue() == null) ? "" : vComponent.getLocation().getValue();
    	locationTextField.setText(initialLocation);
        locationTextField.textProperty().addListener((obs, oldValue, newValue) -> vComponent.setLocation(newValue));
                
        /*
         * END DATE/TIME
         */
        endDateTimeTextField.setLocale(Locale.getDefault());
        endDateTextField.setLocale(Locale.getDefault());
        endDateTimeTextField.setParseErrorCallback(errorCallback);
        endDateTextField.setParseErrorCallback(errorCallback);
        final LocalDateTime end1;
        final LocalDate end2;
        if (vComponent.isWholeDay())
        {
            end1 = LocalDate.from(endRecurrence).minusDays(1).atTime(DEFAULT_START_TIME).plus(DEFAULT_DURATION);
            end2 = LocalDate.from(endRecurrence);
        } else
        {
            end1 = TemporalUtilities.toLocalDateTime(endRecurrence);
            end2 = LocalDate.from(endRecurrence).plusDays(1);
        }
        endDateTimeTextField.setLocalDateTime(end1);
        endDateTextField.setLocalDate(end2);
        endDateTimeTextField.localDateTimeProperty().addListener(endDateTimeTextListener);
        endDateTextField.localDateProperty().addListener(endDateTextListener);
        
        // Ensure end date/time is not before start date/time
        endDateTimeTextField.localDateTimeProperty().addListener((observable, oldSelection, newSelection) ->
        {
            if ((startDateTimeTextField.getLocalDateTime() != null) && newSelection.isBefore(startDateTimeTextField.getLocalDateTime()))
            {
                tooEarlyDateAlert(newSelection, startDateTimeTextField.getLocalDateTime());
                endDateTimeTextField.setLocalDateTime(oldSelection);
            }
        });
        // Ensure end date is not before start date
        endDateTextField.localDateProperty().addListener((observable, oldSelection, newSelection) ->
        {
            if ((startDateTextField.getLocalDate() != null) && newSelection.minusDays(1).isBefore(startDateTextField.getLocalDate()))
            {
                tooEarlyDateAlert(newSelection, startDateTextField.getLocalDate());
                endDateTextField.setLocalDate(oldSelection);
            }
        });
        
        super.setupData(vComponent, startRecurrence, endRecurrence, categories);
    }
    
    // Displays an alert notifying UNTIL date is not an occurrence and changed to 
    private void tooEarlyDateAlert(Temporal t1, Temporal t2)
    {
        Alert alert = new Alert(AlertType.ERROR);
        alert.setTitle("Invalid Date Selection");
        alert.setHeaderText("End must be after start");
        alert.setContentText(t1 + " is not after" + System.lineSeparator() + t2);
        ButtonType buttonTypeOk = new ButtonType("OK", ButtonData.CANCEL_CLOSE);
        alert.getButtonTypes().setAll(buttonTypeOk);
        alert.showAndWait();
    }
    
    /*
     * Change end date/time when whole day is changed
     */
    @Override
    void handleWholeDayChange(T vComponent, Boolean newSelection)
    {
        endDateTimeTextField.localDateTimeProperty().removeListener(endDateTimeTextListener);
        endDateTextField.localDateProperty().removeListener(endDateTextListener);
        super.handleWholeDayChange(vComponent, newSelection);
        if (newSelection)
        {
            timeGridPane.getChildren().remove(endDateTimeTextField);
            timeGridPane.add(endDateTextField, 1, 1);
            endNewRecurrence = endDateTextField.getLocalDate();
        } else
        {
            timeGridPane.getChildren().remove(endDateTextField);
            timeGridPane.add(endDateTimeTextField, 1, 1);
            if (startOriginalRecurrence instanceof LocalDate)
            {
                endNewRecurrence = endDateTimeTextField.getLocalDateTime().atZone(DEFAULT_ZONE_ID);
            } else if (startOriginalRecurrence instanceof LocalDateTime)
            {
                endNewRecurrence = endDateTimeTextField.getLocalDateTime();
            } else if (startOriginalRecurrence instanceof ZonedDateTime)
            {
                ZoneId originalZoneId = ((ZonedDateTime) startOriginalRecurrence).getZone();
                endNewRecurrence = endDateTimeTextField.getLocalDateTime().atZone(originalZoneId);
            } else
            {
                throw new DateTimeException("Unsupported Temporal type:" + startOriginalRecurrence.getClass());
            }
        }
        endDateTextField.localDateProperty().addListener(endDateTextListener);
        endDateTimeTextField.localDateTimeProperty().addListener(endDateTimeTextListener);
//        System.out.println("endNewRecurrence:" + endNewRecurrence);
    }
    
//    /* If startRecurrence isn't valid due to a RRULE change, changes startRecurrence and
//     * endRecurrence to closest valid values
//     */
//    @Override
//    Runnable validateStartRecurrence()
//    {
////        Temporal actualRecurrence = vEvent.streamRecurrences(startRecurrence).findFirst().get();
//        if (! vComponentEdited.isRecurrence(startRecurrenceProperty.get()))
//        {
//            Temporal recurrenceBefore = vComponentEdited.previousStreamValue(startRecurrenceProperty.get());
//            Optional optionalAfter = vComponentEdited.streamRecurrences(startRecurrenceProperty.get()).findFirst();
//            Temporal newStartRecurrence = (optionalAfter.isPresent()) ? optionalAfter.get() : recurrenceBefore;
//            TemporalAmount duration = DateTimeUtilities.temporalAmountBetween(startRecurrenceProperty.get(), endRecurrence);
//            Temporal newEndRecurrence = newStartRecurrence.plus(duration);
//            Temporal startRecurrenceBeforeChange = startRecurrenceProperty.get();
//            startDateTimeTextField.setLocalDateTime(TemporalUtilities.toLocalDateTime(newStartRecurrence));
//            endDateTimeTextField.setLocalDateTime(TemporalUtilities.toLocalDateTime(newEndRecurrence));
//            startOriginalRecurrence = startRecurrenceProperty.get();
//            return () -> startRecurrenceChangedAlert(startRecurrenceBeforeChange, newStartRecurrence);
//        }
//        return null;
//    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy