-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Fix #2806: date editor also accepts incomplete dates * Remove empty line
- Loading branch information
1 parent
a16e612
commit ede4dc8
Showing
7 changed files
with
201 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
|
||
<?import javafx.scene.control.DatePicker?> | ||
<?import javafx.scene.layout.HBox?> | ||
<?import org.jabref.gui.util.component.TemporalAccessorPicker?> | ||
<fx:root xmlns:fx="http://javafx.com/fxml/1" type="HBox" xmlns="http://javafx.com/javafx/8.0.112"> | ||
<DatePicker fx:id="datePicker" prefHeight="0" HBox.hgrow="ALWAYS"/> | ||
<TemporalAccessorPicker fx:id="datePicker" prefHeight="0" HBox.hgrow="ALWAYS"/> | ||
</fx:root> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
src/main/java/org/jabref/gui/util/component/TemporalAccessorPicker.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package org.jabref.gui.util.component; | ||
|
||
import java.time.DateTimeException; | ||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.time.LocalTime; | ||
import java.time.Year; | ||
import java.time.YearMonth; | ||
import java.time.format.DateTimeFormatter; | ||
import java.time.temporal.TemporalAccessor; | ||
import java.time.temporal.TemporalQueries; | ||
|
||
import javafx.beans.property.ObjectProperty; | ||
import javafx.beans.property.SimpleObjectProperty; | ||
import javafx.scene.control.DatePicker; | ||
import javafx.util.StringConverter; | ||
|
||
import org.jabref.gui.util.BindingsHelper; | ||
|
||
/** | ||
* A date picker with configurable datetime format where both date and time can be changed via the text field and the | ||
* date can additionally be changed via the JavaFX default date picker. Also supports incomplete dates. | ||
* | ||
* First recall how the date picker normally works: - The user selects a date in the popup, which sets {@link | ||
* #valueProperty()} to the selected date. - The converter ({@link #converterProperty()}) is used to transform the date | ||
* to a string representation and display it in the text field. | ||
* | ||
* The idea is now to intercept the process and add an additional step: - The user selects a date in the popup, which | ||
* sets {@link #valueProperty()} to the selected date. - The date is converted to a {@link TemporalAccessor} (i.e, | ||
* enriched by a time component) using {@link #addCurrentTime(LocalDate)} - The string converter ({@link | ||
* #stringConverterProperty()}) is used to transform the temporal accessor to a string representation and display it in | ||
* the text field. | ||
* | ||
* Inspiration taken from https://github.com/edvin/tornadofx-controls/blob/master/src/main/java/tornadofx/control/DateTimePicker.java | ||
*/ | ||
public class TemporalAccessorPicker extends DatePicker { | ||
private ObjectProperty<TemporalAccessor> temporalAccessorValue = new SimpleObjectProperty<>(LocalDateTime.now()); | ||
|
||
private DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); | ||
private ObjectProperty<StringConverter<TemporalAccessor>> converter = new SimpleObjectProperty<StringConverter<TemporalAccessor>>(null); | ||
|
||
public TemporalAccessorPicker() { | ||
setConverter(new InternalConverter()); | ||
|
||
// Synchronize changes of the underlying date value with the temporalAccessorValue | ||
BindingsHelper.bindBidirectional(valueProperty(), temporalAccessorValue, | ||
TemporalAccessorPicker::addCurrentTime, | ||
TemporalAccessorPicker::getDate); | ||
} | ||
|
||
private static TemporalAccessor addCurrentTime(LocalDate date) { | ||
if (date == null) { | ||
return null; | ||
} | ||
return LocalDateTime.of(date, LocalTime.now()); | ||
} | ||
|
||
private static LocalDate getDate(TemporalAccessor temporalAccessor) { | ||
if (temporalAccessor == null) { | ||
return null; | ||
} | ||
|
||
return getLocalDate(temporalAccessor); | ||
} | ||
|
||
private static LocalDate getLocalDate(TemporalAccessor dateTime) { | ||
// Try to get as much information from the temporal accessor | ||
LocalDate date = dateTime.query(TemporalQueries.localDate()); | ||
if (date != null) { | ||
return date; | ||
} | ||
|
||
try { | ||
return YearMonth.from(dateTime).atDay(1); | ||
} catch (DateTimeException exception) { | ||
return Year.from(dateTime).atDay(1); | ||
} | ||
} | ||
|
||
public final ObjectProperty<StringConverter<TemporalAccessor>> stringConverterProperty() { | ||
return converter; | ||
} | ||
|
||
public final StringConverter<TemporalAccessor> getStringConverter() { | ||
StringConverter<TemporalAccessor> converter = stringConverterProperty().get(); | ||
if (converter != null) { | ||
return converter; | ||
} else { | ||
return new StringConverter<TemporalAccessor>() { | ||
@Override | ||
public String toString(TemporalAccessor value) { | ||
return defaultFormatter.format(value); | ||
} | ||
|
||
@Override | ||
public TemporalAccessor fromString(String value) { | ||
return LocalDateTime.parse(value, defaultFormatter); | ||
} | ||
}; | ||
} | ||
} | ||
|
||
public final void setStringConverter(StringConverter<TemporalAccessor> value) { | ||
stringConverterProperty().set(value); | ||
} | ||
|
||
public TemporalAccessor getTemporalAccessorValue() { | ||
return temporalAccessorValue.get(); | ||
} | ||
|
||
public void setTemporalAccessorValue(TemporalAccessor temporalAccessorValue) { | ||
this.temporalAccessorValue.set(temporalAccessorValue); | ||
} | ||
|
||
public ObjectProperty<TemporalAccessor> temporalAccessorValueProperty() { | ||
return temporalAccessorValue; | ||
} | ||
|
||
private class InternalConverter extends StringConverter<LocalDate> { | ||
public String toString(LocalDate object) { | ||
TemporalAccessor value = getTemporalAccessorValue(); | ||
return (value != null) ? getStringConverter().toString(value) : ""; | ||
} | ||
|
||
public LocalDate fromString(String value) { | ||
if (value == null || value.isEmpty()) { | ||
temporalAccessorValue.set(null); | ||
return null; | ||
} | ||
|
||
TemporalAccessor dateTime = getStringConverter().fromString(value); | ||
temporalAccessorValue.set(dateTime); | ||
return getLocalDate(dateTime); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters