GNU Classpath (0.17) | ||
Frames | No Frames |
1: /* InternationalFormatter.java -- 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.swing.text; 39: 40: import java.text.AttributedCharacterIterator; 41: import java.text.Format; 42: import java.text.ParseException; 43: import java.util.Iterator; 44: import java.util.Map; 45: import java.util.Set; 46: 47: import javax.swing.Action; 48: import javax.swing.JFormattedTextField; 49: 50: /** 51: * This extends {@link DefaultFormatter} so that the value to string 52: * conversion is done via a {@link Format} object. This allows 53: * various additional formats to be handled by JFormattedField. 54: * 55: * @author Roman Kennke (roman@kennke.org) 56: */ 57: public class InternationalFormatter 58: extends DefaultFormatter 59: { 60: 61: /** The serialVersoinUID. */ 62: private static final long serialVersionUID = 6941977820906408656L; 63: 64: /** The format that handles value to string conversion. */ 65: Format format; 66: 67: /** The minimal permissable value. */ 68: Comparable minimum; 69: 70: /** The maximal permissable value. */ 71: Comparable maximum; 72: 73: /** 74: * Creates a new InternationalFormatter with no Format specified. 75: */ 76: public InternationalFormatter() 77: { 78: super(); 79: minimum = null; 80: maximum = null; 81: format = null; 82: } 83: 84: /** 85: * Creates a new InternationalFormatter that uses the specified 86: * Format object for value to string conversion. 87: * 88: * @param format the Format object to use for value to string conversion 89: */ 90: public InternationalFormatter(Format format) 91: { 92: this(); 93: setFormat(format); 94: } 95: 96: /** 97: * Sets the Format object that is used to convert values to strings. 98: * 99: * @param format the Format to use for value to string conversion 100: * 101: * @see Format 102: */ 103: public void setFormat(Format format) 104: { 105: this.format = format; 106: } 107: 108: /** 109: * Returns the currently used Format object that is used to format 110: * the JFormattedField. 111: * 112: * @return the current Format 113: */ 114: public Format getFormat() 115: { 116: return format; 117: } 118: 119: /** 120: * Sets the minimum value that is allowed by this Formatter. The minimum 121: * value is given as an object that implements the {@link Comparable} 122: * interface. 123: * 124: * If <code>minValue</code> is null, then the Formatter has no restrictions 125: * at the lower end. 126: * 127: * If value class is not yet specified and <code>minValue</code> is not 128: * null, then <code>valueClass</code> is set to the class of the minimum 129: * value. 130: * 131: * @param minValue the minimum permissable value 132: * 133: * @see Comparable 134: */ 135: public void setMinimum(Comparable minValue) 136: { 137: minimum = minValue; 138: if (valueClass == null && minValue != null) 139: valueClass = minValue.getClass(); 140: } 141: 142: /** 143: * Returns the minimal value that is allowed by this Formatter. 144: * 145: * A <code>null</code> value means that there is no restriction. 146: * 147: * @return the minimal value that is allowed by this Formatter or 148: * <code>null</code> if there is no restriction 149: */ 150: public Comparable getMinimum() 151: { 152: return minimum; 153: } 154: 155: /** 156: * Sets the maximum value that is allowed by this Formatter. The maximum 157: * value is given as an object that implements the {@link Comparable} 158: * interface. 159: * 160: * If <code>maxValue</code> is null, then the Formatter has no restrictions 161: * at the upper end. 162: * 163: * If value class is not yet specified and <code>maxValue</code> is not 164: * null, then <code>valueClass</code> is set to the class of the maximum 165: * value. 166: * 167: * @param maxValue the maximum permissable value 168: * 169: * @see Comparable 170: */ 171: public void setMaximum(Comparable maxValue) 172: { 173: maximum = maxValue; 174: if (valueClass == null && maxValue != null) 175: valueClass = maxValue.getClass(); 176: } 177: 178: /** 179: * Returns the maximal value that is allowed by this Formatter. 180: * 181: * A <code>null</code> value means that there is no restriction. 182: * 183: * @return the maximal value that is allowed by this Formatter or 184: * <code>null</code> if there is no restriction 185: */ 186: public Comparable getMaximum() 187: { 188: return maximum; 189: } 190: 191: /** 192: * Installs the formatter on the specified {@link JFormattedTextField}. 193: * 194: * This method does the following things: 195: * <ul> 196: * <li>Display the value of #valueToString in the 197: * <code>JFormattedTextField</code></li> 198: * <li>Install the Actions from #getActions on the <code>JTextField</code> 199: * </li> 200: * <li>Install the DocumentFilter returned by #getDocumentFilter</li> 201: * <li>Install the NavigationFilter returned by #getNavigationFilter</li> 202: * </ul> 203: * 204: * This method is typically not overridden by subclasses. Instead override 205: * one of the mentioned methods in order to customize behaviour. 206: * 207: * @param ftf the {@link JFormattedTextField} in which this formatter 208: * is installed 209: */ 210: public void install(JFormattedTextField ftf) 211: { 212: super.install(ftf); 213: } 214: 215: /** 216: * Converts a value object into a String. This is done by invoking 217: * {@link Format#format} on the specified <code>Format</code> object. 218: * If no format is set, then {@link DefaultFormatter#valueToString(Object)} 219: * is called as a fallback. 220: * 221: * @param value the value to be converted 222: * 223: * @return the string representation of the value 224: * 225: * @throws ParseException if the value cannot be converted 226: */ 227: public String valueToString(Object value) 228: throws ParseException 229: { 230: if (format != null) 231: return format.format(value); 232: else 233: return super.valueToString(value); 234: } 235: 236: /** 237: * Converts a String (from the JFormattedTextField input) to a value. 238: * This is achieved by invoking {@link Format#parseObject(String)} on 239: * the specified <code>Format</code> object. 240: * 241: * This implementation differs slightly from {@link DefaultFormatter}, 242: * it does: 243: * <ol> 244: * <li>Convert the string to an <code>Object</code> using the 245: * <code>Formatter</code>.</li> 246: * <li>If a <code>valueClass</code> has been set, this object is passed to 247: * {@link DefaultFormatter#stringToValue(String)} so that the value 248: * has the correct type. This may or may not work correctly, depending on 249: * the implementation of toString() in the value class and if the class 250: * implements a constructor that takes one String as argument.</li> 251: * <li>If no {@link ParseException} has been thrown so far, we check if the 252: * value exceeds either <code>minimum</code> or <code>maximum</code> if 253: * one of those has been specified and throw a <code>ParseException</code> 254: * if it does.</li> 255: * <li>Return the value.</li> 256: * </ol> 257: * 258: * If no format has been specified, then 259: * {@link DefaultFormatter#stringToValue(String)} is invoked as fallback. 260: * 261: * @param string the string to convert 262: * 263: * @return the value for the string 264: * 265: * @throws ParseException if the string cannot be converted into 266: * a value object (e.g. invalid input) 267: */ 268: public Object stringToValue(String string) 269: throws ParseException 270: { 271: if (format != null) 272: { 273: Object o = format.parseObject(string); 274: 275: // If a value class has been set, call super in order to get 276: // the class right. That is what the JDK API docs suggest, so we do 277: // it that way. 278: if (valueClass != null) 279: o = super.stringToValue(o.toString()); 280: 281: // Check for minimum and maximum bounds 282: if (minimum != null && minimum.compareTo(o) > 0) 283: throw new ParseException("The value may not be less than the" 284: + " specified minimum", 0); 285: if (maximum != null && minimum.compareTo(o) < 0) 286: throw new ParseException("The value may not be greater than the" 287: + " specified maximum", 0); 288: return o; 289: } 290: else 291: return super.stringToValue(string); 292: } 293: 294: /** 295: * Returns the {@link Format.Field} constants that are associated with 296: * the specified position in the text. 297: * 298: * If <code>offset</code> is not a valid location in the input field, 299: * an empty array of fields is returned. 300: * 301: * @param offset the position in the text from which we want to fetch 302: * the fields constants 303: * 304: * @return the field values associated with the specified position in 305: * the text 306: */ 307: public Format.Field[] getFields(int offset) 308: { 309: // TODO: don't know if this is correct 310: AttributedCharacterIterator aci = format.formatToCharacterIterator 311: (getFormattedTextField().getValue()); 312: aci.setIndex(offset); 313: Map atts = aci.getAttributes(); 314: Set keys = atts.keySet(); 315: Format.Field[] fields = new Format.Field[keys.size()]; 316: int index = 0; 317: for (Iterator i = keys.iterator(); i.hasNext(); index++) 318: fields[index] = (Format.Field) i.next(); 319: return fields; 320: } 321: 322: /** 323: * This creates and returns a clone of this Formatter. 324: * 325: * @return a clone of this formatter 326: * 327: * @throws CloneNotSupportedException not thrown here, since cloning is 328: * supported 329: * XXX - FIXME - Whole method disabled as workaround for gcj bug #22060. 330: public Object clone() 331: throws CloneNotSupportedException 332: { 333: // TODO: it has to be considered, if we should return a deep or shallow 334: // clone here. for now we return a shallow clone 335: Object clone = super.clone(); 336: return clone; 337: } 338: */ 339: 340: /** 341: * Returns the Actions that are supported by this Formatter. 342: * 343: * @specnote the JDK API docs say here: <cite>If 344: * <code>getSupportsIncrement</code> returns true, this returns two 345: * Actions suitable for incrementing/decrementing the value.</cite> 346: * The questsion is, which method <code>getSupportsIncrement</code>? 347: * There is no such method in the whole API! So we just call 348: * super.getActions here. 349: */ 350: public Action[] getActions() 351: { 352: return super.getActions(); 353: } 354: }
GNU Classpath (0.17) |