001 /* 002 * $Id: DatePickerFormatter.java 3140 2008-12-16 15:09:09Z kleopatra $ 003 * 004 * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 package org.jdesktop.swingx.calendar; 022 023 import java.text.DateFormat; 024 import java.text.ParseException; 025 import java.text.SimpleDateFormat; 026 import java.util.ArrayList; 027 import java.util.List; 028 import java.util.Locale; 029 import java.util.logging.Logger; 030 031 import javax.swing.JFormattedTextField; 032 import javax.swing.plaf.UIResource; 033 034 import org.jdesktop.swingx.plaf.UIManagerExt; 035 import org.jdesktop.swingx.util.Contract; 036 037 /** 038 * Default formatter for the JXDatePicker component. 039 * It can handle a variety of date formats. 040 * 041 * @author Joshua Outwater 042 */ 043 public class DatePickerFormatter extends 044 JFormattedTextField.AbstractFormatter { 045 046 private static final Logger LOG = Logger 047 .getLogger(DatePickerFormatter.class.getName()); 048 private DateFormat _formats[] = null; 049 050 051 /** 052 * Instantiates a formatter with the localized format patterns defined 053 * in the swingx.properties. 054 * 055 * These formats are localizable and fields may be re-arranged, such as 056 * swapping the month and day fields. The keys for localizing these fields 057 * are: 058 * <ul> 059 * <li>JXDatePicker.longFormat 060 * <li>JXDatePicker.mediumFormat 061 * <li>JXDatePicker.shortFormat 062 * </ul> 063 * 064 */ 065 public DatePickerFormatter() { 066 this(null, null); 067 } 068 069 /** 070 * Instantiates a formatter with the given date formats. If the 071 * array is null, default formats are created from the localized 072 * patterns in swingx.properties. If empty? 073 * 074 * @param formats the array of formats to use. May be null to 075 * use defaults or empty to do nothing (?), but must not contain 076 * null formats. 077 */ 078 public DatePickerFormatter(DateFormat formats[]) { 079 this(formats, null); 080 } 081 082 /** 083 * Instantiates a formatter with default date formats in the 084 * given locale. The default formats are created from the localized 085 * patterns in swingx.properties. 086 * 087 * @param locale the Locale the use for the default formats. 088 */ 089 public DatePickerFormatter(Locale locale) { 090 this(null, locale); 091 } 092 093 /** 094 * Instantiates a formatter with the given formats and locale. 095 * 096 * PENDING JW: makes no sense as a public constructor because the locale is ignored 097 * if the formats are null. So has same public behaviour as the constructor with 098 * formats only ... 099 * 100 * @param formats 101 * @param locale 102 */ 103 public DatePickerFormatter(DateFormat formats[], Locale locale) { 104 // super(); 105 if (locale == null) { 106 locale = Locale.getDefault(); 107 } 108 if (formats == null) { 109 formats = createDefaultFormats(locale); 110 } 111 Contract.asNotNull(formats, "The array of DateFormats must not contain null formats"); 112 _formats = formats; 113 } 114 115 /** 116 * Returns an array of the formats used by this formatter. 117 * 118 * @return the formats used by this formatter, guaranteed to be 119 * not null. 120 */ 121 public DateFormat[] getFormats() { 122 DateFormat[] results = new DateFormat[_formats.length]; 123 System.arraycopy(_formats, 0, results, 0, results.length); 124 return results; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 @Override 131 public Object stringToValue(String text) throws ParseException { 132 Object result = null; 133 ParseException pex = null; 134 135 if (text == null || text.trim().length() == 0) { 136 return null; 137 } 138 139 // If the current formatter did not work loop through the other 140 // formatters and see if any of them can parse the string passed 141 // in. 142 for (DateFormat _format : _formats) { 143 try { 144 result = (_format).parse(text); 145 pex = null; 146 break; 147 } catch (ParseException ex) { 148 pex = ex; 149 } 150 } 151 152 if (pex != null) { 153 throw pex; 154 } 155 156 return result; 157 } 158 159 /** 160 * {@inheritDoc} 161 */ 162 @Override 163 public String valueToString(Object value) throws ParseException { 164 if ((value != null) && (_formats.length > 0)){ 165 return _formats[0].format(value); 166 } 167 return null; 168 } 169 170 /** 171 * Creates and returns the localized default formats. First tries to 172 * add formats created using the patterns stored in the UIManager. If 173 * there are no patterns, use the DateFormat's instance with style 174 * DateFormat.SHORT. 175 * 176 * @return the localized default formats. 177 */ 178 protected DateFormat[] createDefaultFormats(Locale locale) { 179 List<DateFormat> f = new ArrayList<DateFormat>(); 180 addFormat(f, "JXDatePicker.longFormat", locale); 181 addFormat(f, "JXDatePicker.mediumFormat", locale); 182 addFormat(f, "JXDatePicker.shortFormat", locale); 183 if (f.size() == 0) { 184 addSystemDefaultFormat(f, locale); 185 } 186 return f.toArray(new DateFormat[f.size()]); 187 } 188 189 /** 190 * Adds the system's default DateFormat. This implementation adds a 191 * dateInstance of style DateFormat.SHORT. 192 * 193 * @param f the List of formats to add to 194 * @param locale the Locale to use for the formatter. 195 */ 196 private void addSystemDefaultFormat(List<DateFormat> f, Locale locale) { 197 f.add(DateFormat.getDateInstance(DateFormat.SHORT, locale)); 198 } 199 200 /** 201 * Creates and adds a DateFormat to the given list. Looks up 202 * a format pattern registered in the UIManager for the given 203 * key and tries to create a SimpleDateFormat. Does nothing 204 * if there is no format pattern registered or the pattern is 205 * invalid. 206 * 207 * @param f the list of formats 208 * @param key the key for getting the pattern from the UI 209 */ 210 private void addFormat(List<DateFormat> f, String key, Locale locale) { 211 String pattern = UIManagerExt.getString(key, locale); 212 if (pattern == null) return; 213 try { 214 SimpleDateFormat format = new SimpleDateFormat(pattern, locale); 215 f.add(format); 216 } catch (RuntimeException e) { 217 // format string not available or invalid 218 LOG.finer("creating date format failed for key/pattern: " + key + "/" + pattern); 219 } 220 } 221 222 /** 223 * 224 * Same as DatePickerFormatter, but tagged as UIResource. 225 * 226 * @author Jeanette Winzenburg 227 */ 228 public static class DatePickerFormatterUIResource extends DatePickerFormatter 229 implements UIResource { 230 231 /** 232 * @param locale 233 */ 234 public DatePickerFormatterUIResource(Locale locale) { 235 super(locale); 236 } 237 238 /** 239 * 240 */ 241 public DatePickerFormatterUIResource() { 242 this(null); 243 } 244 245 public DatePickerFormatterUIResource(DateFormat[] formats, Locale locale) { 246 super(formats, locale); 247 } 248 } 249 }