214 if (dayCellFactory == null) { 215 dayCellFactory = new SimpleObjectProperty<Callback<DatePicker, DateCell>>(this, "dayCellFactory"); 216 } 217 return dayCellFactory; 218 } 219 220 221 222 /** 223 * The calendar system used for parsing, displaying, and choosing 224 * dates in the DatePicker control. 225 * 226 * <p>The default value is returned from a call to 227 * {@code Chronology.ofLocale(Locale.getDefault(Locale.Category.FORMAT))}. 228 * The default is usually {@link java.time.chrono.IsoChronology} unless 229 * provided explicitly in the {@link java.util.Locale} by use of a 230 * Locale calendar extension. 231 * 232 * Setting the value to <code>null</code> will restore the default 233 * chronology. 234 */ 235 public final ObjectProperty<Chronology> chronologyProperty() { 236 return chronology; 237 } 238 private ObjectProperty<Chronology> chronology = 239 new SimpleObjectProperty<Chronology>(this, "chronology", null); 240 public final Chronology getChronology() { 241 Chronology chrono = chronology.get(); 242 if (chrono == null) { 243 try { 244 chrono = Chronology.ofLocale(Locale.getDefault(Locale.Category.FORMAT)); 245 } catch (Exception ex) { 246 System.err.println(ex); 247 } 248 if (chrono == null) { 249 chrono = IsoChronology.INSTANCE; 250 } 251 //System.err.println(chrono); 252 } 253 return chrono; 254 } 255 public final void setChronology(Chronology value) { 256 chronology.setValue(value); 257 } 258 259 260 /** 261 * Whether the DatePicker popup should display a column showing 262 * week numbers. 263 * 264 * <p>The default value is specified in a resource bundle, and 265 * depends on the country of the current locale. 266 */ 267 public final BooleanProperty showWeekNumbersProperty() { 268 if (showWeekNumbers == null) { 269 String country = Locale.getDefault(Locale.Category.FORMAT).getCountry(); 270 boolean localizedDefault = 271 (!country.isEmpty() && 272 ControlResources.getNonTranslatableString("DatePicker.showWeekNumbers").contains(country)); 273 showWeekNumbers = new StyleableBooleanProperty(localizedDefault) { 274 @Override public CssMetaData<DatePicker,Boolean> getCssMetaData() { 275 return StyleableProperties.SHOW_WEEK_NUMBERS; 276 } 277 278 @Override public Object getBean() { 279 return DatePicker.this; 280 } 281 282 @Override public String getName() { 283 return "showWeekNumbers"; 284 } 285 }; 302 * 303 * <p>If not set by the application, the DatePicker skin class will 304 * set a converter based on a {@link java.time.format.DateTimeFormatter} 305 * for the current {@link java.util.Locale} and 306 * {@link #chronologyProperty() chronology}. This formatter is 307 * then used to parse and display the current date value. 308 * 309 * Setting the value to <code>null</code> will restore the default 310 * converter. 311 * 312 * <p>Example using an explicit formatter: 313 * <pre><code> 314 * datePicker.setConverter(new StringConverter<LocalDate>() { 315 * String pattern = "yyyy-MM-dd"; 316 * DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern); 317 * 318 * { 319 * datePicker.setPromptText(pattern.toLowerCase()); 320 * } 321 * 322 * @Override public String toString(LocalDate date) { 323 * if (date != null) { 324 * return dateFormatter.format(date); 325 * } else { 326 * return ""; 327 * } 328 * } 329 * 330 * @Override public LocalDate fromString(String string) { 331 * if (string != null && !string.isEmpty()) { 332 * return LocalDate.parse(string, dateFormatter); 333 * } else { 334 * return null; 335 * } 336 * } 337 * }); 338 * </code></pre> 339 * <p>Example that wraps the default formatter and catches parse exceptions: 340 * <pre><code> 341 * final StringConverter<LocalDate> defaultConverter = datePicker.getConverter(); 342 * datePicker.setConverter(new StringConverter<LocalDate>() { 343 * @Override public String toString(LocalDate value) { 344 * return defaultConverter.toString(value); 345 * } 346 * 347 * @Override public LocalDate fromString(String text) { 348 * try { 349 * return defaultConverter.fromString(text); 350 * } catch (DateTimeParseException ex) { 351 * System.err.println("HelloDatePicker: "+ex.getMessage()); 352 * throw ex; 353 * } 354 * } 355 * }); 356 * </code></pre> 357 * 358 * <p>The default base year for parsing input containing only two digits for 359 * the year is 2000 (see {@link java.time.format.DateTimeFormatter}). This 360 * default is not useful for allowing a person's date of birth to be typed. 361 * The following example modifies the converter's fromString() method to 362 * allow a two digit year for birth dates up to 99 years in the past. 363 * <pre><code> 364 * @Override public LocalDate fromString(String text) { 365 * if (text != null && !text.isEmpty()) { 366 * Locale locale = Locale.getDefault(Locale.Category.FORMAT); 367 * Chronology chrono = datePicker.getChronology(); 368 * String pattern = 369 * DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, 370 * null, chrono, locale); 371 * String prePattern = pattern.substring(0, pattern.indexOf("y")); 372 * String postPattern = pattern.substring(pattern.lastIndexOf("y")+1); 373 * int baseYear = LocalDate.now().getYear() - 99; 374 * DateTimeFormatter df = new DateTimeFormatterBuilder() 375 * .parseLenient() 376 * .appendPattern(prePattern) 377 * .appendValueReduced(ChronoField.YEAR, 2, 2, baseYear) 378 * .appendPattern(postPattern) 379 * .toFormatter(); 380 * return LocalDate.from(chrono.date(df.parse(text))); 381 * } else { 382 * return null; 383 * } 384 * } 385 * </code></pre> 386 * 387 * @see javafx.scene.control.ComboBox#converterProperty 388 */ 389 public final ObjectProperty<StringConverter<LocalDate>> converterProperty() { return converter; } 390 private ObjectProperty<StringConverter<LocalDate>> converter = 391 new SimpleObjectProperty<StringConverter<LocalDate>>(this, "converter", null); 392 public final void setConverter(StringConverter<LocalDate> value) { converterProperty().set(value); } 393 public final StringConverter<LocalDate> getConverter() { 394 StringConverter<LocalDate> converter = converterProperty().get(); 395 if (converter != null) { 396 return converter; 397 } else { 398 return defaultConverter; 399 } 400 } 401 402 // Create a symmetric (format/parse) converter with the default locale. 403 private StringConverter<LocalDate> defaultConverter = 404 new LocalDateStringConverter(FormatStyle.SHORT, null, getChronology()); 405 406 | 214 if (dayCellFactory == null) { 215 dayCellFactory = new SimpleObjectProperty<Callback<DatePicker, DateCell>>(this, "dayCellFactory"); 216 } 217 return dayCellFactory; 218 } 219 220 221 222 /** 223 * The calendar system used for parsing, displaying, and choosing 224 * dates in the DatePicker control. 225 * 226 * <p>The default value is returned from a call to 227 * {@code Chronology.ofLocale(Locale.getDefault(Locale.Category.FORMAT))}. 228 * The default is usually {@link java.time.chrono.IsoChronology} unless 229 * provided explicitly in the {@link java.util.Locale} by use of a 230 * Locale calendar extension. 231 * 232 * Setting the value to <code>null</code> will restore the default 233 * chronology. 234 * @return the calendar system 235 */ 236 public final ObjectProperty<Chronology> chronologyProperty() { 237 return chronology; 238 } 239 private ObjectProperty<Chronology> chronology = 240 new SimpleObjectProperty<Chronology>(this, "chronology", null); 241 public final Chronology getChronology() { 242 Chronology chrono = chronology.get(); 243 if (chrono == null) { 244 try { 245 chrono = Chronology.ofLocale(Locale.getDefault(Locale.Category.FORMAT)); 246 } catch (Exception ex) { 247 System.err.println(ex); 248 } 249 if (chrono == null) { 250 chrono = IsoChronology.INSTANCE; 251 } 252 //System.err.println(chrono); 253 } 254 return chrono; 255 } 256 public final void setChronology(Chronology value) { 257 chronology.setValue(value); 258 } 259 260 261 /** 262 * Whether the DatePicker popup should display a column showing 263 * week numbers. 264 * 265 * <p>The default value is specified in a resource bundle, and 266 * depends on the country of the current locale. 267 * @return true if popup should display a column showing 268 * week numbers 269 */ 270 public final BooleanProperty showWeekNumbersProperty() { 271 if (showWeekNumbers == null) { 272 String country = Locale.getDefault(Locale.Category.FORMAT).getCountry(); 273 boolean localizedDefault = 274 (!country.isEmpty() && 275 ControlResources.getNonTranslatableString("DatePicker.showWeekNumbers").contains(country)); 276 showWeekNumbers = new StyleableBooleanProperty(localizedDefault) { 277 @Override public CssMetaData<DatePicker,Boolean> getCssMetaData() { 278 return StyleableProperties.SHOW_WEEK_NUMBERS; 279 } 280 281 @Override public Object getBean() { 282 return DatePicker.this; 283 } 284 285 @Override public String getName() { 286 return "showWeekNumbers"; 287 } 288 }; 305 * 306 * <p>If not set by the application, the DatePicker skin class will 307 * set a converter based on a {@link java.time.format.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 * {@literal @Override public String toString(LocalDate date) { 326 * if (date != null) { 327 * return dateFormatter.format(date); 328 * } else { 329 * return ""; 330 * } 331 * }} 332 * 333 * {@literal @Override public LocalDate fromString(String string) { 334 * if (string != null && !string.isEmpty()) { 335 * return LocalDate.parse(string, dateFormatter); 336 * } else { 337 * return null; 338 * } 339 * }} 340 * }); 341 * </code></pre> 342 * <p>Example that wraps the default formatter and catches parse exceptions: 343 * <pre><code> 344 * final StringConverter<LocalDate> defaultConverter = datePicker.getConverter(); 345 * datePicker.setConverter(new StringConverter<LocalDate>() { 346 * @Override public String toString(LocalDate value) { 347 * return defaultConverter.toString(value); 348 * } 349 * 350 * @Override public LocalDate fromString(String text) { 351 * try { 352 * return defaultConverter.fromString(text); 353 * } catch (DateTimeParseException ex) { 354 * System.err.println("HelloDatePicker: "+ex.getMessage()); 355 * throw ex; 356 * } 357 * } 358 * }); 359 * </code></pre> 360 * 361 * <p>The default base year for parsing input containing only two digits for 362 * the year is 2000 (see {@link java.time.format.DateTimeFormatter}). This 363 * default is not useful for allowing a person's date of birth to be typed. 364 * The following example modifies the converter's fromString() method to 365 * allow a two digit year for birth dates up to 99 years in the past. 366 * <pre><code> 367 * {@literal @Override public LocalDate fromString(String text) { 368 * if (text != null && !text.isEmpty()) { 369 * Locale locale = Locale.getDefault(Locale.Category.FORMAT); 370 * Chronology chrono = datePicker.getChronology(); 371 * String pattern = 372 * DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, 373 * null, chrono, locale); 374 * String prePattern = pattern.substring(0, pattern.indexOf("y")); 375 * String postPattern = pattern.substring(pattern.lastIndexOf("y")+1); 376 * int baseYear = LocalDate.now().getYear() - 99; 377 * DateTimeFormatter df = new DateTimeFormatterBuilder() 378 * .parseLenient() 379 * .appendPattern(prePattern) 380 * .appendValueReduced(ChronoField.YEAR, 2, 2, baseYear) 381 * .appendPattern(postPattern) 382 * .toFormatter(); 383 * return LocalDate.from(chrono.date(df.parse(text))); 384 * } else { 385 * return null; 386 * } 387 * }} 388 * </code></pre> 389 * 390 * @return the string converter of type LocalDate 391 * @see javafx.scene.control.ComboBox#converterProperty 392 */ 393 public final ObjectProperty<StringConverter<LocalDate>> converterProperty() { return converter; } 394 private ObjectProperty<StringConverter<LocalDate>> converter = 395 new SimpleObjectProperty<StringConverter<LocalDate>>(this, "converter", null); 396 public final void setConverter(StringConverter<LocalDate> value) { converterProperty().set(value); } 397 public final StringConverter<LocalDate> getConverter() { 398 StringConverter<LocalDate> converter = converterProperty().get(); 399 if (converter != null) { 400 return converter; 401 } else { 402 return defaultConverter; 403 } 404 } 405 406 // Create a symmetric (format/parse) converter with the default locale. 407 private StringConverter<LocalDate> defaultConverter = 408 new LocalDateStringConverter(FormatStyle.SHORT, null, getChronology()); 409 410 |