| /* InternationalFormatter.java -- |
| Copyright (C) 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package javax.swing.text; |
| |
| import java.text.AttributedCharacterIterator; |
| import java.text.Format; |
| import java.text.ParseException; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.swing.Action; |
| import javax.swing.JFormattedTextField; |
| |
| /** |
| * This extends {@link DefaultFormatter} so that the value to string |
| * conversion is done via a {@link Format} object. This allows |
| * various additional formats to be handled by JFormattedField. |
| * |
| * @author Roman Kennke (roman@kennke.org) |
| */ |
| public class InternationalFormatter |
| extends DefaultFormatter |
| { |
| /** The serialization UID (compatible with JDK1.5). */ |
| private static final long serialVersionUID = 2436068675711756856L; |
| |
| /** The format that handles value to string conversion. */ |
| Format format; |
| |
| /** The minimal permissable value. */ |
| Comparable minimum; |
| |
| /** The maximal permissable value. */ |
| Comparable maximum; |
| |
| /** |
| * Creates a new InternationalFormatter with no Format specified. |
| */ |
| public InternationalFormatter() |
| { |
| super(); |
| minimum = null; |
| maximum = null; |
| format = null; |
| setCommitsOnValidEdit(false); |
| setOverwriteMode(false); |
| } |
| |
| /** |
| * Creates a new InternationalFormatter that uses the specified |
| * Format object for value to string conversion. |
| * |
| * @param format the Format object to use for value to string conversion |
| */ |
| public InternationalFormatter(Format format) |
| { |
| this(); |
| setFormat(format); |
| } |
| |
| /** |
| * Sets the Format object that is used to convert values to strings. |
| * |
| * @param format the Format to use for value to string conversion |
| * |
| * @see Format |
| */ |
| public void setFormat(Format format) |
| { |
| this.format = format; |
| } |
| |
| /** |
| * Returns the currently used Format object that is used to format |
| * the JFormattedField. |
| * |
| * @return the current Format |
| */ |
| public Format getFormat() |
| { |
| return format; |
| } |
| |
| /** |
| * Sets the minimum value that is allowed by this Formatter. The minimum |
| * value is given as an object that implements the {@link Comparable} |
| * interface. |
| * |
| * If <code>minValue</code> is null, then the Formatter has no restrictions |
| * at the lower end. |
| * |
| * If value class is not yet specified and <code>minValue</code> is not |
| * null, then <code>valueClass</code> is set to the class of the minimum |
| * value. |
| * |
| * @param minValue the minimum permissable value |
| * |
| * @see Comparable |
| */ |
| public void setMinimum(Comparable minValue) |
| { |
| minimum = minValue; |
| if (valueClass == null && minValue != null) |
| valueClass = minValue.getClass(); |
| } |
| |
| /** |
| * Returns the minimal value that is allowed by this Formatter. |
| * |
| * A <code>null</code> value means that there is no restriction. |
| * |
| * @return the minimal value that is allowed by this Formatter or |
| * <code>null</code> if there is no restriction |
| */ |
| public Comparable getMinimum() |
| { |
| return minimum; |
| } |
| |
| /** |
| * Sets the maximum value that is allowed by this Formatter. The maximum |
| * value is given as an object that implements the {@link Comparable} |
| * interface. |
| * |
| * If <code>maxValue</code> is null, then the Formatter has no restrictions |
| * at the upper end. |
| * |
| * If value class is not yet specified and <code>maxValue</code> is not |
| * null, then <code>valueClass</code> is set to the class of the maximum |
| * value. |
| * |
| * @param maxValue the maximum permissable value |
| * |
| * @see Comparable |
| */ |
| public void setMaximum(Comparable maxValue) |
| { |
| maximum = maxValue; |
| if (valueClass == null && maxValue != null) |
| valueClass = maxValue.getClass(); |
| } |
| |
| /** |
| * Returns the maximal value that is allowed by this Formatter. |
| * |
| * A <code>null</code> value means that there is no restriction. |
| * |
| * @return the maximal value that is allowed by this Formatter or |
| * <code>null</code> if there is no restriction |
| */ |
| public Comparable getMaximum() |
| { |
| return maximum; |
| } |
| |
| /** |
| * Installs the formatter on the specified {@link JFormattedTextField}. |
| * |
| * This method does the following things: |
| * <ul> |
| * <li>Display the value of #valueToString in the |
| * <code>JFormattedTextField</code></li> |
| * <li>Install the Actions from #getActions on the <code>JTextField</code> |
| * </li> |
| * <li>Install the DocumentFilter returned by #getDocumentFilter</li> |
| * <li>Install the NavigationFilter returned by #getNavigationFilter</li> |
| * </ul> |
| * |
| * This method is typically not overridden by subclasses. Instead override |
| * one of the mentioned methods in order to customize behaviour. |
| * |
| * @param ftf the {@link JFormattedTextField} in which this formatter |
| * is installed |
| */ |
| public void install(JFormattedTextField ftf) |
| { |
| super.install(ftf); |
| } |
| |
| /** |
| * Converts a value object into a String. This is done by invoking |
| * {@link Format#format(Object)} on the specified <code>Format</code> object. |
| * If no format is set, then {@link DefaultFormatter#valueToString(Object)} |
| * is called as a fallback. |
| * |
| * @param value the value to be converted |
| * |
| * @return the string representation of the value |
| * |
| * @throws ParseException if the value cannot be converted |
| */ |
| public String valueToString(Object value) |
| throws ParseException |
| { |
| if (value == null) |
| return ""; |
| if (format != null) |
| return format.format(value); |
| else |
| return super.valueToString(value); |
| } |
| |
| /** |
| * Converts a String (from the JFormattedTextField input) to a value. |
| * This is achieved by invoking {@link Format#parseObject(String)} on |
| * the specified <code>Format</code> object. |
| * |
| * This implementation differs slightly from {@link DefaultFormatter}, |
| * it does: |
| * <ol> |
| * <li>Convert the string to an <code>Object</code> using the |
| * <code>Formatter</code>.</li> |
| * <li>If a <code>valueClass</code> has been set, this object is passed to |
| * {@link DefaultFormatter#stringToValue(String)} so that the value |
| * has the correct type. This may or may not work correctly, depending on |
| * the implementation of toString() in the value class and if the class |
| * implements a constructor that takes one String as argument.</li> |
| * <li>If no {@link ParseException} has been thrown so far, we check if the |
| * value exceeds either <code>minimum</code> or <code>maximum</code> if |
| * one of those has been specified and throw a <code>ParseException</code> |
| * if it does.</li> |
| * <li>Return the value.</li> |
| * </ol> |
| * |
| * If no format has been specified, then |
| * {@link DefaultFormatter#stringToValue(String)} is invoked as fallback. |
| * |
| * @param string the string to convert |
| * |
| * @return the value for the string |
| * |
| * @throws ParseException if the string cannot be converted into |
| * a value object (e.g. invalid input) |
| */ |
| public Object stringToValue(String string) |
| throws ParseException |
| { |
| if (format != null) |
| { |
| Object o = format.parseObject(string); |
| |
| // If a value class has been set, call super in order to get |
| // the class right. That is what the JDK API docs suggest, so we do |
| // it that way. |
| if (valueClass != null) |
| o = super.stringToValue(o.toString()); |
| |
| // Check for minimum and maximum bounds |
| if (minimum != null && minimum.compareTo(o) > 0) |
| throw new ParseException("The value may not be less than the" |
| + " specified minimum", 0); |
| if (maximum != null && minimum.compareTo(o) < 0) |
| throw new ParseException("The value may not be greater than the" |
| + " specified maximum", 0); |
| return o; |
| } |
| else |
| return super.stringToValue(string); |
| } |
| |
| /** |
| * Returns the {@link Format.Field} constants that are associated with |
| * the specified position in the text. |
| * |
| * If <code>offset</code> is not a valid location in the input field, |
| * an empty array of fields is returned. |
| * |
| * @param offset the position in the text from which we want to fetch |
| * the fields constants |
| * |
| * @return the field values associated with the specified position in |
| * the text |
| */ |
| public Format.Field[] getFields(int offset) |
| { |
| // TODO: don't know if this is correct |
| AttributedCharacterIterator aci = format.formatToCharacterIterator |
| (getFormattedTextField().getValue()); |
| aci.setIndex(offset); |
| Map atts = aci.getAttributes(); |
| Set keys = atts.keySet(); |
| Format.Field[] fields = new Format.Field[keys.size()]; |
| int index = 0; |
| for (Iterator i = keys.iterator(); i.hasNext(); index++) |
| fields[index] = (Format.Field) i.next(); |
| return fields; |
| } |
| |
| /** |
| * This creates and returns a clone of this Formatter. |
| * |
| * @return a clone of this formatter |
| * |
| * @throws CloneNotSupportedException not thrown here, since cloning is |
| * supported |
| * XXX - FIXME - Whole method disabled as workaround for gcj bug #22060. |
| public Object clone() |
| throws CloneNotSupportedException |
| { |
| // TODO: it has to be considered, if we should return a deep or shallow |
| // clone here. for now we return a shallow clone |
| Object clone = super.clone(); |
| return clone; |
| } |
| */ |
| |
| /** |
| * Returns the Actions that are supported by this Formatter. |
| * |
| * @specnote the JDK API docs say here: <cite>If |
| * <code>getSupportsIncrement</code> returns true, this returns two |
| * Actions suitable for incrementing/decrementing the value.</cite> |
| * The questsion is, which method <code>getSupportsIncrement</code>? |
| * There is no such method in the whole API! So we just call |
| * super.getActions here. |
| */ |
| protected Action[] getActions() |
| { |
| return super.getActions(); |
| } |
| } |