diff --git a/src/main/java/de/doubleslash/keeptime/App.java b/src/main/java/de/doubleslash/keeptime/App.java index 2c3ff0a3..1abc87ec 100644 --- a/src/main/java/de/doubleslash/keeptime/App.java +++ b/src/main/java/de/doubleslash/keeptime/App.java @@ -21,9 +21,11 @@ import java.io.StringWriter; import java.time.LocalDate; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.stream.Collectors; +import de.doubleslash.keeptime.common.DateFormatter; import javafx.stage.Window; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,6 +86,8 @@ public class App extends Application { @Override public void init() throws Exception { LOG.info("Starting KeepTime."); + DateFormatter.setSystemLocale(Locale.getDefault()); + Locale.setDefault(Locale.ENGLISH); final DefaultExceptionHandler defaultExceptionHandler = new DefaultExceptionHandler(); defaultExceptionHandler.register(); diff --git a/src/main/java/de/doubleslash/keeptime/common/DateFormatter.java b/src/main/java/de/doubleslash/keeptime/common/DateFormatter.java index 5b876a24..da6eda52 100644 --- a/src/main/java/de/doubleslash/keeptime/common/DateFormatter.java +++ b/src/main/java/de/doubleslash/keeptime/common/DateFormatter.java @@ -16,15 +16,23 @@ package de.doubleslash.keeptime.common; +import javafx.scene.control.DatePicker; +import javafx.util.StringConverter; + import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.format.FormatStyle; +import java.util.Locale; public class DateFormatter { private static DateTimeFormatter dayDateFormatter = DateTimeFormatter.ofPattern("eeee dd.MM.yyyy"); private static DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + private static Locale systemLocale = Locale.getDefault(); + private DateFormatter() { throw new IllegalStateException("Utility class: DateFormatter"); } @@ -55,4 +63,36 @@ public static String toTimeString(final LocalDateTime localDateTime) { return localDateTime.format(timeFormatter); } + public static void setSystemLocale(Locale locale) { + systemLocale = locale; + } + + public static Locale getSystemLocale() { + return systemLocale; + } + + public static void applySystemLocaleOnDate(DatePicker datePicker) { + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(systemLocale); + + datePicker.setConverter(new StringConverter<>() { + @Override + public String toString(LocalDate date) { + return (date != null) ? formatter.format(date) : ""; + } + + @Override + public LocalDate fromString(String s) { + try { + return (s != null && !s.isEmpty()) ? LocalDate.parse(s, formatter) : null; + } catch (DateTimeParseException e) { + return null; + } + } + }); + + datePicker.setOnShowing(e-> Locale.setDefault(Locale.Category.FORMAT, systemLocale)); + datePicker.setOnHiding(e-> Locale.setDefault(Locale.Category.FORMAT, Locale.getDefault())); + datePicker.setOnAction(e-> Locale.setDefault(Locale.Category.FORMAT, Locale.getDefault())); + datePicker.setPromptText(formatter.format(LocalDate.now())); + } } diff --git a/src/main/java/de/doubleslash/keeptime/view/ExternalProjectsSyncController.java b/src/main/java/de/doubleslash/keeptime/view/ExternalProjectsSyncController.java index 0f6dac2f..e472b9af 100644 --- a/src/main/java/de/doubleslash/keeptime/view/ExternalProjectsSyncController.java +++ b/src/main/java/de/doubleslash/keeptime/view/ExternalProjectsSyncController.java @@ -124,7 +124,9 @@ public class ExternalProjectsSyncController { private final Color colorLoadingSuccess = Color.valueOf("#74a317"); private final Color colorLoadingFailure = Color.valueOf("#c63329"); - private final LocalTimeStringConverter localTimeStringConverter = new LocalTimeStringConverter(FormatStyle.MEDIUM); + private final LocalTimeStringConverter localTimeStringConverter = new LocalTimeStringConverter( + FormatStyle.MEDIUM, + DateFormatter.getSystemLocale()); private ObservableList items; private LocalDate currentReportDate; @@ -579,8 +581,10 @@ private void showErrorDialog(List errorMessages) { } private void setUpTimeSpinner(final Spinner spinner) { + final LocalTimeStringConverter stringConverter = new LocalTimeStringConverter( + FormatStyle.MEDIUM, + DateFormatter.getSystemLocale()); spinner.focusedProperty().addListener(e -> { - final LocalTimeStringConverter stringConverter = new LocalTimeStringConverter(FormatStyle.MEDIUM); final StringProperty text = spinner.getEditor().textProperty(); try { stringConverter.fromString(text.get()); @@ -621,7 +625,7 @@ public void increment(final int steps) { }); - spinner.getValueFactory().setConverter(new LocalTimeStringConverter(FormatStyle.MEDIUM)); + spinner.getValueFactory().setConverter(stringConverter); } public static LocalTime decrementToLastFullQuarter(LocalTime time) { diff --git a/src/main/java/de/doubleslash/keeptime/view/ManageWorkController.java b/src/main/java/de/doubleslash/keeptime/view/ManageWorkController.java index b9455b93..db8f1bfa 100644 --- a/src/main/java/de/doubleslash/keeptime/view/ManageWorkController.java +++ b/src/main/java/de/doubleslash/keeptime/view/ManageWorkController.java @@ -21,6 +21,7 @@ import java.time.format.DateTimeParseException; import java.time.format.FormatStyle; +import de.doubleslash.keeptime.common.DateFormatter; import javafx.scene.control.skin.ComboBoxListViewSkin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -120,6 +121,9 @@ private void initialize() { private void setUpTimeRestriction() { + DateFormatter.applySystemLocaleOnDate(startDatePicker); + DateFormatter.applySystemLocaleOnDate(endDatePicker); + BooleanBinding isValidBinding = Bindings.createBooleanBinding(() -> { if (startTimeSpinner.getValue() == null || endTimeSpinner.getValue() == null || startDatePicker.getValue() == null || endDatePicker.getValue() == null) { @@ -150,8 +154,11 @@ private void setUpTimeRestriction() { } private void setUpTimeSpinner(final Spinner spinner) { + final LocalTimeStringConverter stringConverter = new LocalTimeStringConverter( + FormatStyle.MEDIUM, + DateFormatter.getSystemLocale() + ); spinner.focusedProperty().addListener((e) -> { - final LocalTimeStringConverter stringConverter = new LocalTimeStringConverter(FormatStyle.MEDIUM); final StringProperty text = spinner.getEditor().textProperty(); try { stringConverter.fromString(text.get()); @@ -188,7 +195,7 @@ public void increment(final int steps) { }); - spinner.getValueFactory().setConverter(new LocalTimeStringConverter(FormatStyle.MEDIUM)); + spinner.getValueFactory().setConverter(stringConverter); } diff --git a/src/main/java/de/doubleslash/keeptime/view/ReportController.java b/src/main/java/de/doubleslash/keeptime/view/ReportController.java index 5d714518..3933cbd6 100644 --- a/src/main/java/de/doubleslash/keeptime/view/ReportController.java +++ b/src/main/java/de/doubleslash/keeptime/view/ReportController.java @@ -355,14 +355,13 @@ private void updateReport(final LocalDate dateToShow) { private void loadCalenderWidget() { final DatePicker myDatePicker = new DatePicker(this.currentReportDate); + DateFormatter.applySystemLocaleOnDate(myDatePicker); myDatePicker.valueProperty().addListener((observable, oldvalue, newvalue) -> { LOG.info("Datepicker selected value changed to {}", newvalue); updateReport(newvalue); }); - // HACK to show calendar from datepicker - // https://stackoverflow.com/questions/34681975/javafx-extract-calendar-popup-from-datepicker-only-show-popup - final DatePickerSkin datePickerSkin = new DatePickerSkin(myDatePicker); + final Callback dayCellFactory = callback -> new DateCell() { @Override public void updateItem(final LocalDate item, final boolean empty) { @@ -378,9 +377,19 @@ public void updateItem(final LocalDate item, final boolean empty) { }; myDatePicker.setDayCellFactory(dayCellFactory); - final Node popupContent = datePickerSkin.getPopupContent(); - this.topBorderPane.setRight(popupContent); + Locale defaultLocale = Locale.getDefault(); + try { + Locale.setDefault(DateFormatter.getSystemLocale()); + + // HACK to show calendar from datepicker + // https://stackoverflow.com/questions/34681975/javafx-extract-calendar-popup-from-datepicker-only-show-popup + final DatePickerSkin datePickerSkin = new DatePickerSkin(myDatePicker); + final Node popupContent = datePickerSkin.getPopupContent(); + this.topBorderPane.setRight(popupContent); + } finally { + Locale.setDefault(defaultLocale); + } } private Button createDeleteWorkButton(final Work w) { diff --git a/src/test/java/de/doubleslash/keeptime/common/DateFormatterTest.java b/src/test/java/de/doubleslash/keeptime/common/DateFormatterTest.java index f3f63b6f..2c081465 100644 --- a/src/test/java/de/doubleslash/keeptime/common/DateFormatterTest.java +++ b/src/test/java/de/doubleslash/keeptime/common/DateFormatterTest.java @@ -18,12 +18,17 @@ import static org.hamcrest.MatcherAssert.assertThat; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.Locale; +import javafx.scene.control.DatePicker; import org.hamcrest.Matchers; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + @Disabled class DateFormatterTest {