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 }