--- old/modules/controls/src/main/java/javafx/scene/control/DatePicker.java 2014-08-04 16:58:36.775035679 -0700 +++ new/modules/controls/src/main/java/javafx/scene/control/DatePicker.java 2014-08-04 16:58:36.623035678 -0700 @@ -32,11 +32,7 @@ import java.time.chrono.Chronology; import java.time.chrono.ChronoLocalDate; import java.time.chrono.IsoChronology; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.DecimalStyle; import java.time.format.FormatStyle; -import java.time.temporal.TemporalAccessor; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -58,6 +54,7 @@ import javafx.scene.AccessibleRole; import javafx.util.Callback; import javafx.util.StringConverter; +import javafx.util.converter.LocalDateStringConverter; import com.sun.javafx.css.converters.BooleanConverter; import com.sun.javafx.scene.control.skin.DatePickerSkin; @@ -136,6 +133,7 @@ if (validateDate(chrono, date)) { lastValidChronology = chrono; + defaultConverter = new LocalDateStringConverter(FormatStyle.SHORT, null, chrono); } else { System.err.println("Restoring value to " + lastValidChronology); setChronology(lastValidChronology); @@ -304,7 +302,7 @@ * versa. * *

If not set by the application, the DatePicker skin class will - * set a converter based on a {@link java.time.DateTimeFormatter} + * set a converter based on a {@link java.time.format.DateTimeFormatter} * for the current {@link java.util.Locale} and * {@link #chronologyProperty() chronology}. This formatter is * then used to parse and display the current date value. @@ -402,64 +400,9 @@ } } - private StringConverter defaultConverter = new StringConverter() { - @Override public String toString(LocalDate value) { - if (value != null) { - Locale locale = Locale.getDefault(Locale.Category.FORMAT); - Chronology chrono = getChronology(); - ChronoLocalDate cDate; - try { - cDate = chrono.date(value); - } catch (DateTimeException ex) { - System.err.println(ex); - chrono = IsoChronology.INSTANCE; - cDate = value; - } - DateTimeFormatter dateFormatter = - DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) - .withLocale(locale) - .withChronology(chrono) - .withDecimalStyle(DecimalStyle.of(locale)); - - String pattern = - DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, - null, chrono, locale); - - if (pattern.contains("yy") && !pattern.contains("yyy")) { - // Modify pattern to show four-digit year, including leading zeros. - String newPattern = pattern.replace("yy", "yyyy"); - //System.err.println("Fixing pattern ("+forParsing+"): "+pattern+" -> "+newPattern); - dateFormatter = DateTimeFormatter.ofPattern(newPattern) - .withDecimalStyle(DecimalStyle.of(locale)); - } - - return dateFormatter.format(cDate); - } else { - return ""; - } - } - - @Override public LocalDate fromString(String text) { - if (text != null && !text.isEmpty()) { - Locale locale = Locale.getDefault(Locale.Category.FORMAT); - Chronology chrono = getChronology(); - - String pattern = - DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, - null, chrono, locale); - DateTimeFormatter df = - new DateTimeFormatterBuilder().parseLenient() - .appendPattern(pattern) - .toFormatter() - .withChronology(chrono) - .withDecimalStyle(DecimalStyle.of(locale)); - TemporalAccessor temporal = df.parse(text); - ChronoLocalDate cDate = chrono.date(temporal); - return LocalDate.from(cDate); - } - return null; - } - }; + // Create a symmetric (format/parse) converter with the default locale. + private StringConverter defaultConverter = + new LocalDateStringConverter(FormatStyle.SHORT, null, getChronology()); // --- Editor --- old/modules/controls/src/test/java/javafx/scene/control/DatePickerTest.java 2014-08-04 16:58:37.559035686 -0700 +++ new/modules/controls/src/test/java/javafx/scene/control/DatePickerTest.java 2014-08-04 16:58:37.403035685 -0700 @@ -385,12 +385,10 @@ ********************************************************************/ @Test public void test_rt30549() { - StringConverter converter = datePicker.getConverter(); - // Set a MinguoDate from a String datePicker.setChronology(MinguoChronology.INSTANCE); datePicker.getEditor().setText("5/22/0102 1"); - datePicker.setValue(converter.fromString(datePicker.getEditor().getText())); + datePicker.setValue(datePicker.getConverter().fromString(datePicker.getEditor().getText())); assertEquals(MinguoChronology.INSTANCE.date(MinguoEra.ROC, 102, 5, 22), MinguoDate.from(datePicker.getValue())); assertEquals("5/22/0102 1", datePicker.getEditor().getText()); @@ -398,7 +396,7 @@ // Convert from MinguoDate to LocalDate (ISO) datePicker.setChronology(IsoChronology.INSTANCE); assertEquals(LocalDate.of(2013, 5, 22), datePicker.getValue()); - datePicker.getEditor().setText(converter.toString(datePicker.getValue())); + datePicker.getEditor().setText(datePicker.getConverter().toString(datePicker.getValue())); assertEquals("5/22/2013", datePicker.getEditor().getText()); } --- /dev/null 2014-07-27 19:38:16.499796011 -0700 +++ new/modules/base/src/main/java/javafx/util/converter/LocalDateStringConverter.java 2014-08-04 16:58:38.151035691 -0700 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.util.converter; + +import java.time.LocalDate; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Locale; + +import javafx.util.StringConverter; +import javafx.util.converter.LocalDateTimeStringConverter.LdtConverter; + +/** + *

{@link StringConverter} implementation for {@link LocalDate} values.

+ * + * @see LocalTimeStringConverter + * @see LocalDateTimeStringConverter + * @since JavaFX 8u40 + */ +public class LocalDateStringConverter extends StringConverter { + + LdtConverter ldtConverter; + + // ------------------------------------------------------------ Constructors + + /** + * Create a {@link StringConverter} for {@link LocalDate} values, using a + * default formatter and parser based on {@link IsoChronology}, + * {@link FormatStyle#SHORT}, and the user's {@link Locale}. + * + *

This converter ensures symmetry between the toString() and + * fromString() methods. Many of the default locale based patterns used by + * {@link DateTimeFormatter} will display only two digits for the year when + * formatting to a string. This would cause a value like 1955 to be + * displayed as 55, which in turn would be parsed back as 2055. This + * converter modifies two-digit year patterns to always use four digits. The + * input parsing is not affected, so two digit year values can still be + * parsed leniently as expected in these locales.

+ */ + public LocalDateStringConverter() { + ldtConverter = new LdtConverter(LocalDate.class, null, null, + null, null, null, null); + } + + /** + * Create a {@link StringConverter} for {@link LocalDate} values, using a + * default formatter and parser based on {@link IsoChronology}, + * the specified {@link FormatStyle}, and the user's {@link Locale}. + * + * @param dateStyle The {@link FormatStyle} that will be used by the default + * formatter and parser. If null then {@link FormatStyle#SHORT} will be used. + */ + public LocalDateStringConverter(FormatStyle dateStyle) { + ldtConverter = new LdtConverter(LocalDate.class, null, null, + dateStyle, null, null, null); + } + + /** + * Create a {#link StringConverter} for {@link LocalDate} values using the supplied + * formatter and parser. + * + *

For example, to use a fixed pattern for converting both ways:

+ *
+     * String pattern = "yyyy-MM-dd";
+     * DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
+     * StringConverter converter =
+     *     DateTimeStringConverter.getLocalDateStringConverter(formatter, null);
+     * 
+ * + * Note that the formatter and parser can be created to handle non-default + * {@link Locale} and {@link Chronology} as needed. + * + * @param formatter An instance of {@link DateTimeFormatter} that will be + * used for formatting by the toString() method. If null then a default + * formatter will be used. + * @param parser An instance of {@link DateTimeFormatter} that will be used + * for parsing by the fromString() method. This can be identical to + * formatter. If null then formatter will be used, and if that is also null, + * then a default parser will be used. + */ + public LocalDateStringConverter(DateTimeFormatter formatter, DateTimeFormatter parser) { + ldtConverter = new LdtConverter(LocalDate.class, formatter, parser, + null, null, null, null); + } + + + /** + * Create a StringConverter for {@link LocalDate} values using a default + * formatter and parser, which will be based on the supplied + * {@link FormatStyle}, {@link Locale}, and {@link Chronology}. + * + * @param dateStyle The {@link FormatStyle} that will be used by the default + * formatter and parser. If null then {@link FormatStyle#SHORT} will be used. + * @param locale The {@link Locale} that will be used by the default + * formatter and parser. If null then + * {@code Locale.getDefault(Locale.Category.FORMAT)} will be used. + * @param chronology The {@link Chronology} that will be used by the default + * formatter and parser. If null then {@link IsoChronology#INSTANCE} will be used. + */ + public LocalDateStringConverter(FormatStyle dateStyle, Locale locale, Chronology chronology) { + ldtConverter = new LdtConverter(LocalDate.class, null, null, + dateStyle, null, locale, chronology); + } + + // ------------------------------------------------------- Converter Methods + + /** {@inheritDoc} */ + @Override public LocalDate fromString(String value) { + return ldtConverter.fromString(value); + } + + /** {@inheritDoc} */ + @Override public String toString(LocalDate value) { + return ldtConverter.toString(value); + } + +} --- /dev/null 2014-07-27 19:38:16.499796011 -0700 +++ new/modules/base/src/main/java/javafx/util/converter/LocalDateTimeStringConverter.java 2014-08-04 16:58:38.859035697 -0700 @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.util.converter; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.LocalDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DecimalStyle; +import java.time.format.FormatStyle; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.Locale; + +import javafx.util.StringConverter; + +/** + *

{@link StringConverter} implementation for {@link LocalDateTime} values.

+ * + * @see LocalDateStringConverter + * @see LocalTimeStringConverter + * @since JavaFX 8u40 + */ +public class LocalDateTimeStringConverter extends StringConverter { + + LdtConverter ldtConverter; + + + + // ------------------------------------------------------------ Constructors + + /** + * Create a {@link StringConverter} for {@link LocalDateTime} values, using a + * default formatter and parser based on {@link IsoChronology}, + * {@link FormatStyle#SHORT} for both date and time, and the user's + * {@link Locale}. + * + *

This converter ensures symmetry between the toString() and + * fromString() methods. Many of the default locale based patterns used by + * {@link DateTimeFormatter} will display only two digits for the year when + * formatting to a string. This would cause a value like 1955 to be + * displayed as 55, which in turn would be parsed back as 2055. This + * converter modifies two-digit year patterns to always use four digits. The + * input parsing is not affected, so two digit year values can still be + * parsed as expected in these locales.

+ */ + public LocalDateTimeStringConverter() { + ldtConverter = new LdtConverter(LocalDateTime.class, null, null, + null, null, null, null); + } + + /** + * Create a {@link StringConverter} for {@link LocalDateTime} values, using + * a default formatter and parser based on {@link IsoChronology}, the + * specified {@link FormatStyle} values for date and time, and the user's + * {@link Locale}. + * + * @param dateStyle The {@link FormatStyle} that will be used by the default + * formatter and parser for the date. If null then {@link FormatStyle#SHORT} + * will be used. + * @param timeStyle The {@link FormatStyle} that will be used by the default + * formatter and parser for the time. If null then {@link FormatStyle#SHORT} + * will be used. + */ + public LocalDateTimeStringConverter(FormatStyle dateStyle, FormatStyle timeStyle) { + ldtConverter = new LdtConverter(LocalDateTime.class, null, null, + dateStyle, timeStyle, null, null); + } + + /** + * Create a {@link StringConverter} for {@link LocalDateTime} values using + * the supplied formatter and parser. + * + *

For example, to use a fixed pattern for converting both ways:

+ *
+     * String pattern = "yyyy-MM-dd HH:mm";
+     * DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
+     * StringConverter converter =
+     *     DateTimeStringConverter.getLocalDateTimeConverter(formatter, null);
+     * 
+ * + * Note that the formatter and parser can be created to handle non-default + * {@link Locale} and {@link Chronology} as needed. + * + * @param formatter An instance of {@link DateTimeFormatter} which will be + * used for formatting by the toString() method. If null then a default + * formatter will be used. + * @param parser An instance of {@link DateTimeFormatter} which will be used + * for parsing by the fromString() method. This can be identical to + * formatter. If null then formatter will be used, and if that is also null, + * then a default parser will be used. + */ + public LocalDateTimeStringConverter(DateTimeFormatter formatter, DateTimeFormatter parser) { + ldtConverter = new LdtConverter(LocalDateTime.class, formatter, parser, + null, null, null, null); + } + + /** + * Create a {@link StringConverter} for {@link LocalDateTime} values using a + * default formatter and parser, which will be based on the supplied + * {@link FormatStyle}s, {@link Locale}, and {@link Chronology}. + * + * @param dateStyle The {@link FormatStyle} that will be used by the default + * formatter and parser for the date. If null then {@link FormatStyle#SHORT} + * will be used. + * @param timeStyle The {@link FormatStyle} that will be used by the default + * formatter and parser for the time. If null then {@link FormatStyle#SHORT} + * will be used. + * @param locale The {@link Locale} that will be used by the + * default formatter and parser. If null then + * {@code Locale.getDefault(Locale.Category.FORMAT)} will be used. + * @param chronology The {@link Chronology} that will be used by the default + * formatter and parser. If null then {@link IsoChronology#INSTANCE} will be + * used. + */ + public LocalDateTimeStringConverter(FormatStyle dateStyle, FormatStyle timeStyle, + Locale locale, Chronology chronology) { + ldtConverter = new LdtConverter(LocalDateTime.class, null, null, + dateStyle, timeStyle, locale, chronology); + } + + + + // ------------------------------------------------------- Converter Methods + + /** {@inheritDoc} */ + @Override public LocalDateTime fromString(String value) { + return ldtConverter.fromString(value); + } + + /** {@inheritDoc} */ + @Override public String toString(LocalDateTime value) { + return ldtConverter.toString(value); + } + + + + static class LdtConverter extends StringConverter { + private Class type; + Locale locale; + Chronology chronology; + DateTimeFormatter formatter; + DateTimeFormatter parser; + FormatStyle dateStyle; + FormatStyle timeStyle; + + LdtConverter(Class type, DateTimeFormatter formatter, DateTimeFormatter parser, + FormatStyle dateStyle, FormatStyle timeStyle, Locale locale, Chronology chronology) { + this.type = type; + this.formatter = formatter; + this.parser = (parser != null) ? parser : formatter; + this.locale = (locale != null) ? locale : Locale.getDefault(Locale.Category.FORMAT); + this.chronology = (chronology != null) ? chronology : IsoChronology.INSTANCE; + + if (type == LocalDate.class || type == LocalDateTime.class) { + this.dateStyle = (dateStyle != null) ? dateStyle : FormatStyle.SHORT; + } + + if (type == LocalTime.class || type == LocalDateTime.class) { + this.timeStyle = (timeStyle != null) ? timeStyle : FormatStyle.SHORT; + } + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + @Override public T fromString(String text) { + if (text == null || text.isEmpty()) { + return null; + } + + text = text.trim(); + + if (parser == null) { + parser = getDefaultParser(); + } + + TemporalAccessor temporal = parser.parse(text); + + if (type == LocalDate.class) { + return (T)LocalDate.from(chronology.date(temporal)); + } else if (type == LocalTime.class) { + return (T)LocalTime.from(temporal); + } else { + return (T)LocalDateTime.from(chronology.localDateTime(temporal)); + } + } + + + /** {@inheritDoc} */ + @Override public String toString(T value) { + // If the specified value is null, return a zero-length String + if (value == null) { + return ""; + } + + if (formatter == null) { + formatter = getDefaultFormatter(); + } + + if (value instanceof LocalDate) { + ChronoLocalDate cDate; + try { + cDate = chronology.date(value); + } catch (DateTimeException ex) { + System.err.println(ex); + chronology = IsoChronology.INSTANCE; + cDate = (LocalDate)value; + } + return formatter.format(cDate); + } else if (value instanceof LocalDateTime) { + ChronoLocalDateTime cDateTime; + try { + cDateTime = chronology.localDateTime(value); + } catch (DateTimeException ex) { + System.err.println(ex); + chronology = IsoChronology.INSTANCE; + cDateTime = (LocalDateTime)value; + } + return formatter.format(cDateTime); + } else { + return formatter.format(value); + } + } + + + private DateTimeFormatter getDefaultParser() { + String pattern = + DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, timeStyle, + chronology, locale); + return new DateTimeFormatterBuilder().parseLenient() + .appendPattern(pattern) + .toFormatter() + .withChronology(chronology) + .withDecimalStyle(DecimalStyle.of(locale)); + } + + /** + *

Return a default DateTimeFormatter instance to use for formatting + * and parsing in this {@link StringConverter}.

+ */ + private DateTimeFormatter getDefaultFormatter() { + DateTimeFormatter formatter; + + if (dateStyle != null && timeStyle != null) { + formatter = DateTimeFormatter.ofLocalizedDateTime(dateStyle, timeStyle); + } else if (dateStyle != null) { + formatter = DateTimeFormatter.ofLocalizedDate(dateStyle); + } else { + formatter = DateTimeFormatter.ofLocalizedTime(timeStyle); + } + + formatter = formatter.withLocale(locale) + .withChronology(chronology) + .withDecimalStyle(DecimalStyle.of(locale)); + + if (dateStyle != null) { + formatter = fixFourDigitYear(formatter, dateStyle, timeStyle, + chronology, locale); + } + + return formatter; + } + + private DateTimeFormatter fixFourDigitYear(DateTimeFormatter formatter, + FormatStyle dateStyle, FormatStyle timeStyle, + Chronology chronology, Locale locale) { + String pattern = + DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, timeStyle, + chronology, locale); + if (pattern.contains("yy") && !pattern.contains("yyy")) { + // Modify pattern to show four-digit year, including leading zeros. + String newPattern = pattern.replace("yy", "yyyy"); + formatter = DateTimeFormatter.ofPattern(newPattern) + .withDecimalStyle(DecimalStyle.of(locale)); + } + + return formatter; + } + } +} --- /dev/null 2014-07-27 19:38:16.499796011 -0700 +++ new/modules/base/src/main/java/javafx/util/converter/LocalTimeStringConverter.java 2014-08-04 16:58:39.567035703 -0700 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.util.converter; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Locale; + +import javafx.util.StringConverter; +import javafx.util.converter.LocalDateTimeStringConverter.LdtConverter; + +/** + *

{@link StringConverter} implementation for {@link LocalTime} values.

+ * + * @see LocalDateStringConverter + * @see LocalDateTimeStringConverter + * @since JavaFX 8u40 + */ +public class LocalTimeStringConverter extends StringConverter { + + LdtConverter ldtConverter; + + // ------------------------------------------------------------ Constructors + + /** + * Create a {@link StringConverter} for {@link LocalTime} values, using a + * default formatter and parser with {@link FormatStyle#SHORT}, and the + * user's {@link Locale}. + */ + public LocalTimeStringConverter() { + ldtConverter = new LdtConverter(LocalTime.class, null, null, + null, null, null, null); + } + + /** + * Create a {@link StringConverter} for {@link LocalTime} values, using a + * default formatter and parser with the specified {@link FormatStyle} and + * based on the user's {@link Locale}. + * + * @param timeStyle The {@link FormatStyle} that will be used by the default + * formatter and parser. If null then {@link FormatStyle#SHORT} will be used. + */ + public LocalTimeStringConverter(FormatStyle timeStyle) { + ldtConverter = new LdtConverter(LocalTime.class, null, null, + null, timeStyle, null, null); + } + + /** + * Create a StringConverter for {@link LocalTime} values, using a + * default formatter and parser with the specified {@link FormatStyle} + * and {@link Locale}. + * + * @param timeStyle The {@link FormatStyle} that will be used by the default + * formatter and parser. If null then {@link FormatStyle#SHORT} will be used. + * @param locale The {@link Locale} that will be used by the default + * formatter and parser. If null then + * {@code Locale.getDefault(Locale.Category.FORMAT)} will be used. + */ + public LocalTimeStringConverter(FormatStyle timeStyle, Locale locale) { + ldtConverter = new LdtConverter(LocalTime.class, null, null, + null, timeStyle, locale, null); + } + + /** + * Create a StringConverter for {@link LocalTime} values using the + * supplied formatter and parser, which are responsible for + * choosing the desired {@link Locale}. + * + *

For example, a fixed pattern can be used for converting both ways:

+ *
+     * String pattern = "HH:mm:ss";
+     * DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
+     * StringConverter converter =
+     *     DateTimeStringConverter.getLocalTimeConverter(formatter, null);
+     * 
+ * + * @param formatter An instance of {@link DateTimeFormatter} which + * will be used for formatting by the toString() method. If null + * then a default formatter will be used. + * @param parser An instance of {@link DateTimeFormatter} which + * will be used for parsing by the fromString() method. This can + * be identical to formatter. If null, then formatter will be + * used, and if that is also null, then a default parser will be + * used. + */ + public LocalTimeStringConverter(DateTimeFormatter formatter, DateTimeFormatter parser) { + ldtConverter = new LdtConverter(LocalTime.class, formatter, parser, + null, null, null, null); + } + + // ------------------------------------------------------- Converter Methods + + /** {@inheritDoc} */ + @Override public LocalTime fromString(String value) { + return ldtConverter.fromString(value); + } + + /** {@inheritDoc} */ + @Override public String toString(LocalTime value) { + return ldtConverter.toString(value); + } +} --- /dev/null 2014-07-27 19:38:16.499796011 -0700 +++ new/modules/base/src/test/java/javafx/util/converter/LocalDateStringConverterTest.java 2014-08-04 16:58:40.283035709 -0700 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.util.converter; + +import java.util.Arrays; +import java.time.LocalDate; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Collection; +import java.util.Locale; + +import javafx.util.StringConverter; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + */ +@RunWith(Parameterized.class) +public class LocalDateStringConverterTest { + private static final LocalDate VALID_DATE = LocalDate.of(1985, 1, 12); + + private static final DateTimeFormatter aFormatter = DateTimeFormatter.ofPattern("dd MM yyyy"); + private static final DateTimeFormatter aParser = DateTimeFormatter.ofPattern("yyyy MM dd"); + + + @Parameterized.Parameters public static Collection implementations() { + return Arrays.asList(new Object[][] { + { new LocalDateStringConverter(), + Locale.getDefault(Locale.Category.FORMAT), FormatStyle.SHORT, + VALID_DATE, null, null }, + + { new LocalDateStringConverter(aFormatter, aParser), + Locale.getDefault(Locale.Category.FORMAT), null, + VALID_DATE, aFormatter, aParser }, + + { new LocalDateStringConverter(FormatStyle.SHORT, Locale.UK, IsoChronology.INSTANCE), + Locale.UK, FormatStyle.SHORT, + VALID_DATE, null, null }, + }); + } + + private LocalDateStringConverter converter; + private Locale locale; + private FormatStyle dateStyle; + private DateTimeFormatter formatter, parser; + private LocalDate validDate; + + public LocalDateStringConverterTest(LocalDateStringConverter converter, Locale locale, FormatStyle dateStyle, LocalDate validDate, DateTimeFormatter formatter, DateTimeFormatter parser) { + this.converter = converter; + this.locale = locale; + this.dateStyle = dateStyle; + this.validDate = validDate; + this.formatter = formatter; + this.parser = parser; + } + + @Before public void setup() { + } + + /********************************************************************* + * Test constructors + ********************************************************************/ + + @Test public void testConstructor() { + assertEquals(locale, converter.ldtConverter.locale); + assertEquals((dateStyle != null) ? dateStyle : FormatStyle.SHORT, converter.ldtConverter.dateStyle); + assertNull(converter.ldtConverter.timeStyle); + if (formatter != null) { + assertEquals(formatter, converter.ldtConverter.formatter); + } + if (parser != null) { + assertEquals(parser, converter.ldtConverter.parser); + } else if (formatter != null) { + assertEquals(formatter, converter.ldtConverter.parser); + } + } + + + /********************************************************************* + * Test toString / fromString methods + ********************************************************************/ + + @Test public void toString_to_fromString_testRoundtrip() { + if (formatter == null) { + // Only the default formatter/parser can guarantee roundtrip symmetry + assertEquals(validDate, converter.fromString(converter.toString(validDate))); + } + } + + @Test(expected=RuntimeException.class) + public void fromString_testInvalidInput() { + converter.fromString("abcdefg"); + } +} --- /dev/null 2014-07-27 19:38:16.499796011 -0700 +++ new/modules/base/src/test/java/javafx/util/converter/LocalDateTimeStringConverterTest.java 2014-08-04 16:58:40.983035715 -0700 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.util.converter; + +import java.time.LocalDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Arrays; +import java.util.Collection; +import java.util.Locale; +import static org.junit.Assert.*; + +import javafx.util.StringConverter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + */ +@RunWith(Parameterized.class) +public class LocalDateTimeStringConverterTest { + private static final LocalDateTime VALID_LDT_WITH_SECONDS = LocalDateTime.of(1985, 1, 12, 12, 34, 56); + private static final LocalDateTime VALID_LDT_WITHOUT_SECONDS = LocalDateTime.of(1985, 1, 12, 12, 34, 0); + + private static final DateTimeFormatter aFormatter = DateTimeFormatter.ofPattern("dd MM yyyy HH mm ss"); + private static final DateTimeFormatter aParser = DateTimeFormatter.ofPattern("yyyy MM dd hh mm ss a"); + + @Parameterized.Parameters public static Collection implementations() { + return Arrays.asList(new Object[][] { + { new LocalDateTimeStringConverter(), + Locale.getDefault(Locale.Category.FORMAT), FormatStyle.SHORT, FormatStyle.SHORT, + VALID_LDT_WITHOUT_SECONDS, null, null }, + + { new LocalDateTimeStringConverter(aFormatter, aParser), + Locale.getDefault(Locale.Category.FORMAT), null, null, + VALID_LDT_WITH_SECONDS, aFormatter, aParser }, + + { new LocalDateTimeStringConverter(FormatStyle.SHORT, FormatStyle.SHORT, Locale.UK, IsoChronology.INSTANCE), + Locale.UK, FormatStyle.SHORT, FormatStyle.SHORT, + VALID_LDT_WITHOUT_SECONDS, null, null }, + }); + } + + private LocalDateTimeStringConverter converter; + private Locale locale; + private FormatStyle dateStyle; + private FormatStyle timeStyle; + private DateTimeFormatter formatter, parser; + + private LocalDateTime validDateTime; + + public LocalDateTimeStringConverterTest(LocalDateTimeStringConverter converter, Locale locale, FormatStyle dateStyle, FormatStyle timeStyle, LocalDateTime validDateTime, DateTimeFormatter formatter, DateTimeFormatter parser) { + this.converter = converter; + this.locale = locale; + this.dateStyle = dateStyle; + this.timeStyle = timeStyle; + this.validDateTime = validDateTime; + this.formatter = formatter; + this.parser = parser; + } + + @Before public void setup() { + } + + /********************************************************************* + * Test constructors + ********************************************************************/ + + @Test public void testConstructor() { + assertEquals(locale, converter.ldtConverter.locale); + assertEquals((dateStyle != null) ? dateStyle : FormatStyle.SHORT, converter.ldtConverter.dateStyle); + assertEquals((timeStyle != null) ? timeStyle : FormatStyle.SHORT, converter.ldtConverter.timeStyle); + if (formatter != null) { + assertEquals(formatter, converter.ldtConverter.formatter); + } + if (parser != null) { + assertEquals(parser, converter.ldtConverter.parser); + } else if (formatter != null) { + assertEquals(formatter, converter.ldtConverter.parser); + } + } + + + /********************************************************************* + * Test toString / fromString methods + ********************************************************************/ + + @Test public void toString_to_fromString_testRoundtrip() { + if (formatter == null) { + // Only the default formatter/parser can guarantee roundtrip symmetry + assertEquals(validDateTime, converter.fromString(converter.toString(validDateTime))); + } + } + + + @Test(expected=RuntimeException.class) + public void fromString_testInvalidInput() { + converter.fromString("abcdefg"); + } + + @Test public void converter_with_specified_formatter_and_parser() { + String formatPattern = "dd MMMM yyyy, HH:mm:ss"; + String parsePattern = "MMMM dd, yyyy, HH:mm:ss"; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern); + DateTimeFormatter parser = DateTimeFormatter.ofPattern(parsePattern); + StringConverter converter = new LocalDateTimeStringConverter(formatter, parser); + assertEquals("12 January 1985, 12:34:56", converter.toString(VALID_LDT_WITH_SECONDS)); + assertEquals(VALID_LDT_WITH_SECONDS, converter.fromString("January 12, 1985, 12:34:56")); + } + + @Test public void converter_with_specified_formatter_and_null_parser() { + String pattern = "dd MMMM yyyy, HH:mm:ss"; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + StringConverter converter = new LocalDateTimeStringConverter(formatter, null); + assertEquals("12 January 1985, 12:34:56", converter.toString(VALID_LDT_WITH_SECONDS)); + assertEquals(VALID_LDT_WITH_SECONDS, converter.fromString("12 January 1985, 12:34:56")); + } +} --- /dev/null 2014-07-27 19:38:16.499796011 -0700 +++ new/modules/base/src/test/java/javafx/util/converter/LocalTimeStringConverterTest.java 2014-08-04 16:58:41.719035721 -0700 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javafx.util.converter; + +import java.time.LocalTime; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Arrays; +import java.util.Collection; +import java.util.Locale; + +import javafx.util.StringConverter; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + */ +@RunWith(Parameterized.class) +public class LocalTimeStringConverterTest { + private static final LocalTime VALID_TIME_WITH_SECONDS; + private static final LocalTime VALID_TIME_WITHOUT_SECONDS; + + static { + VALID_TIME_WITH_SECONDS = LocalTime.of(12, 34, 56); + VALID_TIME_WITHOUT_SECONDS = LocalTime.of(12, 34, 0); + } + + private static final DateTimeFormatter aFormatter = DateTimeFormatter.ofPattern("HH mm ss"); + private static final DateTimeFormatter aParser = DateTimeFormatter.ofPattern("hh mm ss a"); + + + @Parameterized.Parameters public static Collection implementations() { + return Arrays.asList(new Object[][] { + { new LocalTimeStringConverter(), + Locale.getDefault(Locale.Category.FORMAT), FormatStyle.SHORT, + VALID_TIME_WITHOUT_SECONDS, null, null }, + + { new LocalTimeStringConverter(aFormatter, aParser), + Locale.getDefault(Locale.Category.FORMAT), null, + VALID_TIME_WITH_SECONDS, aFormatter, aParser }, + + { new LocalTimeStringConverter(FormatStyle.SHORT, Locale.UK), + Locale.UK, FormatStyle.SHORT, + VALID_TIME_WITHOUT_SECONDS, null, null }, + }); + } + + private LocalTimeStringConverter converter; + private Locale locale; + private FormatStyle timeStyle; + private DateTimeFormatter formatter, parser; + private LocalTime validTime; + + public LocalTimeStringConverterTest(LocalTimeStringConverter converter, Locale locale, FormatStyle timeStyle, LocalTime validTime, DateTimeFormatter formatter, DateTimeFormatter parser) { + this.converter = converter; + this.locale = locale; + this.timeStyle = timeStyle; + this.validTime = validTime; + this.formatter = formatter; + this.parser = parser; + } + + @Before public void setup() { + } + + /********************************************************************* + * Test constructors + ********************************************************************/ + + @Test public void testConstructor() { + assertEquals(locale, converter.ldtConverter.locale); + assertNull(converter.ldtConverter.dateStyle); + assertEquals((timeStyle != null) ? timeStyle : FormatStyle.SHORT, converter.ldtConverter.timeStyle); + if (formatter != null) { + assertEquals(formatter, converter.ldtConverter.formatter); + } + if (parser != null) { + assertEquals(parser, converter.ldtConverter.parser); + } else if (formatter != null) { + assertEquals(formatter, converter.ldtConverter.parser); + } + } + + + + /********************************************************************* + * Test toString / fromString methods + ********************************************************************/ + + @Test public void toString_to_fromString_testRoundtrip() { + if (formatter == null) { + // Only the default formatter/parser can guarantee roundtrip symmetry + assertEquals(validTime, converter.fromString(converter.toString(validTime))); + } + } + + @Test(expected=RuntimeException.class) + public void fromString_testInvalidInput() { + converter.fromString("abcdefg"); + } +}