15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.scene.control;
27
28 // editor and converter code in sync with ComboBox 4858:e60e9a5396e6
29
30 import java.time.LocalDate;
31 import java.time.DateTimeException;
32 import java.time.chrono.Chronology;
33 import java.time.chrono.ChronoLocalDate;
34 import java.time.chrono.IsoChronology;
35 import java.time.format.DateTimeFormatter;
36 import java.time.format.DateTimeFormatterBuilder;
37 import java.time.format.DecimalStyle;
38 import java.time.format.FormatStyle;
39 import java.time.temporal.TemporalAccessor;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.List;
43 import java.util.Locale;
44
45 import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin;
46
47 import javafx.beans.property.BooleanProperty;
48 import javafx.beans.property.ObjectProperty;
49 import javafx.beans.property.ReadOnlyObjectProperty;
50 import javafx.beans.property.ReadOnlyObjectWrapper;
51 import javafx.beans.property.SimpleObjectProperty;
52 import javafx.beans.value.WritableValue;
53 import javafx.css.CssMetaData;
54 import javafx.css.Styleable;
55 import javafx.css.StyleableBooleanProperty;
56 import javafx.css.StyleableProperty;
57 import javafx.scene.AccessibleAttribute;
58 import javafx.scene.AccessibleRole;
59 import javafx.util.Callback;
60 import javafx.util.StringConverter;
61
62 import com.sun.javafx.css.converters.BooleanConverter;
63 import com.sun.javafx.scene.control.skin.DatePickerSkin;
64 import com.sun.javafx.scene.control.skin.resources.ControlResources;
65
66
67 /**
68 * The DatePicker control allows the user to enter a date as text or
69 * to select a date from a calendar popup. The calendar is based on
70 * either the standard ISO-8601 chronology or any of the other
71 * chronology classes defined in the java.time.chrono package.
72 *
73 * <p>The {@link #valueProperty() value} property represents the
74 * currently selected {@link java.time.LocalDate}. An initial date can
75 * be set via the {@link #DatePicker(java.time.LocalDate) constructor}
76 * or by calling {@link #setValue(java.time.LocalDate) setValue()}. The
77 * default value is null.
78 *
79 * <pre><code>
80 * final DatePicker datePicker = new DatePicker();
119
120 valueProperty().addListener(observable -> {
121 LocalDate date = getValue();
122 Chronology chrono = getChronology();
123
124 if (validateDate(chrono, date)) {
125 lastValidDate = date;
126 } else {
127 System.err.println("Restoring value to " +
128 ((lastValidDate == null) ? "null" : getConverter().toString(lastValidDate)));
129 setValue(lastValidDate);
130 }
131 });
132
133 chronologyProperty().addListener(observable -> {
134 LocalDate date = getValue();
135 Chronology chrono = getChronology();
136
137 if (validateDate(chrono, date)) {
138 lastValidChronology = chrono;
139 } else {
140 System.err.println("Restoring value to " + lastValidChronology);
141 setChronology(lastValidChronology);
142 }
143 });
144 }
145
146 private boolean validateDate(Chronology chrono, LocalDate date) {
147 try {
148 if (date != null) {
149 chrono.date(date);
150 }
151 return true;
152 } catch (DateTimeException ex) {
153 System.err.println(ex);
154 return false;
155 }
156 }
157
158 /**
287 }
288 };
289 }
290 return showWeekNumbers;
291 }
292 private BooleanProperty showWeekNumbers;
293 public final void setShowWeekNumbers(boolean value) {
294 showWeekNumbersProperty().setValue(value);
295 }
296 public final boolean isShowWeekNumbers() {
297 return showWeekNumbersProperty().getValue();
298 }
299
300
301 // --- string converter
302 /**
303 * Converts the input text to an object of type LocalDate and vice
304 * versa.
305 *
306 * <p>If not set by the application, the DatePicker skin class will
307 * set a converter based on a {@link java.time.DateTimeFormatter}
308 * for the current {@link java.util.Locale} and
309 * {@link #chronologyProperty() chronology}. This formatter is
310 * then used to parse and display the current date value.
311 *
312 * Setting the value to <code>null</code> will restore the default
313 * converter.
314 *
315 * <p>Example using an explicit formatter:
316 * <pre><code>
317 * datePicker.setConverter(new StringConverter<LocalDate>() {
318 * String pattern = "yyyy-MM-dd";
319 * DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
320 *
321 * {
322 * datePicker.setPromptText(pattern.toLowerCase());
323 * }
324 *
325 * @Override public String toString(LocalDate date) {
326 * if (date != null) {
327 * return dateFormatter.format(date);
385 * return null;
386 * }
387 * }
388 * </code></pre>
389 *
390 * @see javafx.scene.control.ComboBox#converterProperty
391 */
392 public final ObjectProperty<StringConverter<LocalDate>> converterProperty() { return converter; }
393 private ObjectProperty<StringConverter<LocalDate>> converter =
394 new SimpleObjectProperty<StringConverter<LocalDate>>(this, "converter", null);
395 public final void setConverter(StringConverter<LocalDate> value) { converterProperty().set(value); }
396 public final StringConverter<LocalDate> getConverter() {
397 StringConverter<LocalDate> converter = converterProperty().get();
398 if (converter != null) {
399 return converter;
400 } else {
401 return defaultConverter;
402 }
403 }
404
405 private StringConverter<LocalDate> defaultConverter = new StringConverter<LocalDate>() {
406 @Override public String toString(LocalDate value) {
407 if (value != null) {
408 Locale locale = Locale.getDefault(Locale.Category.FORMAT);
409 Chronology chrono = getChronology();
410 ChronoLocalDate cDate;
411 try {
412 cDate = chrono.date(value);
413 } catch (DateTimeException ex) {
414 System.err.println(ex);
415 chrono = IsoChronology.INSTANCE;
416 cDate = value;
417 }
418 DateTimeFormatter dateFormatter =
419 DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
420 .withLocale(locale)
421 .withChronology(chrono)
422 .withDecimalStyle(DecimalStyle.of(locale));
423
424 String pattern =
425 DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT,
426 null, chrono, locale);
427
428 if (pattern.contains("yy") && !pattern.contains("yyy")) {
429 // Modify pattern to show four-digit year, including leading zeros.
430 String newPattern = pattern.replace("yy", "yyyy");
431 //System.err.println("Fixing pattern ("+forParsing+"): "+pattern+" -> "+newPattern);
432 dateFormatter = DateTimeFormatter.ofPattern(newPattern)
433 .withDecimalStyle(DecimalStyle.of(locale));
434 }
435
436 return dateFormatter.format(cDate);
437 } else {
438 return "";
439 }
440 }
441
442 @Override public LocalDate fromString(String text) {
443 if (text != null && !text.isEmpty()) {
444 Locale locale = Locale.getDefault(Locale.Category.FORMAT);
445 Chronology chrono = getChronology();
446
447 String pattern =
448 DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT,
449 null, chrono, locale);
450 DateTimeFormatter df =
451 new DateTimeFormatterBuilder().parseLenient()
452 .appendPattern(pattern)
453 .toFormatter()
454 .withChronology(chrono)
455 .withDecimalStyle(DecimalStyle.of(locale));
456 TemporalAccessor temporal = df.parse(text);
457 ChronoLocalDate cDate = chrono.date(temporal);
458 return LocalDate.from(cDate);
459 }
460 return null;
461 }
462 };
463
464
465 // --- Editor
466 /**
467 * The editor for the DatePicker.
468 *
469 * @see javafx.scene.control.ComboBox#editorProperty
470 */
471 private ReadOnlyObjectWrapper<TextField> editor;
472 public final TextField getEditor() {
473 return editorProperty().get();
474 }
475 public final ReadOnlyObjectProperty<TextField> editorProperty() {
476 if (editor == null) {
477 editor = new ReadOnlyObjectWrapper<TextField>(this, "editor");
478 editor.set(new ComboBoxListViewSkin.FakeFocusTextField());
479 }
480 return editor.getReadOnlyProperty();
481 }
482
|
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.scene.control;
27
28 // editor and converter code in sync with ComboBox 4858:e60e9a5396e6
29
30 import java.time.LocalDate;
31 import java.time.DateTimeException;
32 import java.time.chrono.Chronology;
33 import java.time.chrono.ChronoLocalDate;
34 import java.time.chrono.IsoChronology;
35 import java.time.format.FormatStyle;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.Locale;
40
41 import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin;
42
43 import javafx.beans.property.BooleanProperty;
44 import javafx.beans.property.ObjectProperty;
45 import javafx.beans.property.ReadOnlyObjectProperty;
46 import javafx.beans.property.ReadOnlyObjectWrapper;
47 import javafx.beans.property.SimpleObjectProperty;
48 import javafx.beans.value.WritableValue;
49 import javafx.css.CssMetaData;
50 import javafx.css.Styleable;
51 import javafx.css.StyleableBooleanProperty;
52 import javafx.css.StyleableProperty;
53 import javafx.scene.AccessibleAttribute;
54 import javafx.scene.AccessibleRole;
55 import javafx.util.Callback;
56 import javafx.util.StringConverter;
57 import javafx.util.converter.LocalDateStringConverter;
58
59 import com.sun.javafx.css.converters.BooleanConverter;
60 import com.sun.javafx.scene.control.skin.DatePickerSkin;
61 import com.sun.javafx.scene.control.skin.resources.ControlResources;
62
63
64 /**
65 * The DatePicker control allows the user to enter a date as text or
66 * to select a date from a calendar popup. The calendar is based on
67 * either the standard ISO-8601 chronology or any of the other
68 * chronology classes defined in the java.time.chrono package.
69 *
70 * <p>The {@link #valueProperty() value} property represents the
71 * currently selected {@link java.time.LocalDate}. An initial date can
72 * be set via the {@link #DatePicker(java.time.LocalDate) constructor}
73 * or by calling {@link #setValue(java.time.LocalDate) setValue()}. The
74 * default value is null.
75 *
76 * <pre><code>
77 * final DatePicker datePicker = new DatePicker();
116
117 valueProperty().addListener(observable -> {
118 LocalDate date = getValue();
119 Chronology chrono = getChronology();
120
121 if (validateDate(chrono, date)) {
122 lastValidDate = date;
123 } else {
124 System.err.println("Restoring value to " +
125 ((lastValidDate == null) ? "null" : getConverter().toString(lastValidDate)));
126 setValue(lastValidDate);
127 }
128 });
129
130 chronologyProperty().addListener(observable -> {
131 LocalDate date = getValue();
132 Chronology chrono = getChronology();
133
134 if (validateDate(chrono, date)) {
135 lastValidChronology = chrono;
136 defaultConverter = new LocalDateStringConverter(FormatStyle.SHORT, null, chrono);
137 } else {
138 System.err.println("Restoring value to " + lastValidChronology);
139 setChronology(lastValidChronology);
140 }
141 });
142 }
143
144 private boolean validateDate(Chronology chrono, LocalDate date) {
145 try {
146 if (date != null) {
147 chrono.date(date);
148 }
149 return true;
150 } catch (DateTimeException ex) {
151 System.err.println(ex);
152 return false;
153 }
154 }
155
156 /**
285 }
286 };
287 }
288 return showWeekNumbers;
289 }
290 private BooleanProperty showWeekNumbers;
291 public final void setShowWeekNumbers(boolean value) {
292 showWeekNumbersProperty().setValue(value);
293 }
294 public final boolean isShowWeekNumbers() {
295 return showWeekNumbersProperty().getValue();
296 }
297
298
299 // --- string converter
300 /**
301 * Converts the input text to an object of type LocalDate and vice
302 * versa.
303 *
304 * <p>If not set by the application, the DatePicker skin class will
305 * set a converter based on a {@link java.time.format.DateTimeFormatter}
306 * for the current {@link java.util.Locale} and
307 * {@link #chronologyProperty() chronology}. This formatter is
308 * then used to parse and display the current date value.
309 *
310 * Setting the value to <code>null</code> will restore the default
311 * converter.
312 *
313 * <p>Example using an explicit formatter:
314 * <pre><code>
315 * datePicker.setConverter(new StringConverter<LocalDate>() {
316 * String pattern = "yyyy-MM-dd";
317 * DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern);
318 *
319 * {
320 * datePicker.setPromptText(pattern.toLowerCase());
321 * }
322 *
323 * @Override public String toString(LocalDate date) {
324 * if (date != null) {
325 * return dateFormatter.format(date);
383 * return null;
384 * }
385 * }
386 * </code></pre>
387 *
388 * @see javafx.scene.control.ComboBox#converterProperty
389 */
390 public final ObjectProperty<StringConverter<LocalDate>> converterProperty() { return converter; }
391 private ObjectProperty<StringConverter<LocalDate>> converter =
392 new SimpleObjectProperty<StringConverter<LocalDate>>(this, "converter", null);
393 public final void setConverter(StringConverter<LocalDate> value) { converterProperty().set(value); }
394 public final StringConverter<LocalDate> getConverter() {
395 StringConverter<LocalDate> converter = converterProperty().get();
396 if (converter != null) {
397 return converter;
398 } else {
399 return defaultConverter;
400 }
401 }
402
403 // Create a symmetric (format/parse) converter with the default locale.
404 private StringConverter<LocalDate> defaultConverter =
405 new LocalDateStringConverter(FormatStyle.SHORT, null, getChronology());
406
407
408 // --- Editor
409 /**
410 * The editor for the DatePicker.
411 *
412 * @see javafx.scene.control.ComboBox#editorProperty
413 */
414 private ReadOnlyObjectWrapper<TextField> editor;
415 public final TextField getEditor() {
416 return editorProperty().get();
417 }
418 public final ReadOnlyObjectProperty<TextField> editorProperty() {
419 if (editor == null) {
420 editor = new ReadOnlyObjectWrapper<TextField>(this, "editor");
421 editor.set(new ComboBoxListViewSkin.FakeFocusTextField());
422 }
423 return editor.getReadOnlyProperty();
424 }
425
|