jfxtras.internal.scene.control.skin.agenda.icalendar.base24hour.popup.EditDescriptiveLocatableVBox Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jfxtras-all Show documentation
Show all versions of jfxtras-all Show documentation
Miscellaneous components for JavaFX
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;
// }
}