mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			559 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			559 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* MaskFormatter.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 gnu.java.lang.CPStringBuilder;
 | |
| 
 | |
| import java.text.ParseException;
 | |
| 
 | |
| import javax.swing.JFormattedTextField;
 | |
| 
 | |
| /**
 | |
|  * @author Anthony Balkissoon abalkiss at redhat dot com
 | |
|  *
 | |
|  */
 | |
| public class MaskFormatter extends DefaultFormatter
 | |
| {
 | |
|   // The declaration of the valid mask characters
 | |
|   private static final char NUM_CHAR = '#';
 | |
|   private static final char ESCAPE_CHAR = '\'';
 | |
|   private static final char UPPERCASE_CHAR = 'U';
 | |
|   private static final char LOWERCASE_CHAR = 'L';
 | |
|   private static final char ALPHANUM_CHAR = 'A';
 | |
|   private static final char LETTER_CHAR = '?';
 | |
|   private static final char ANYTHING_CHAR = '*';
 | |
|   private static final char HEX_CHAR = 'H';
 | |
| 
 | |
|   /** The mask for this MaskFormatter **/
 | |
|   private String mask;
 | |
| 
 | |
|   /**
 | |
|    * A String made up of the characters that are not valid for input for
 | |
|    * this MaskFormatter.
 | |
|    */
 | |
|   private String invalidChars;
 | |
| 
 | |
|   /**
 | |
|    * A String made up of the characters that are valid for input for
 | |
|    * this MaskFormatter.
 | |
|    */
 | |
|   private String validChars;
 | |
| 
 | |
|   /** A String used in place of missing chracters if the value does not
 | |
|    * completely fill in the spaces in the mask.
 | |
|    */
 | |
|   private String placeHolder;
 | |
| 
 | |
|   /** A character used in place of missing characters if the value does
 | |
|    * not completely fill in the spaces in the mask.
 | |
|    */
 | |
|   private char placeHolderChar = ' ';
 | |
| 
 | |
|   /**
 | |
|    * Whether or not stringToValue should return literal characters in the mask.
 | |
|    */
 | |
|   private boolean valueContainsLiteralCharacters = true;
 | |
| 
 | |
|   /** A String used for easy access to valid HEX characters **/
 | |
|   private static String hexString = "0123456789abcdefABCDEF";
 | |
| 
 | |
|   /** An int to hold the length of the mask, accounting for escaped characters **/
 | |
|   int maskLength = 0;
 | |
| 
 | |
|   public MaskFormatter ()
 | |
|   {
 | |
|     // Override super's default behaviour, in MaskFormatter the default
 | |
|     // is not to allow invalid values
 | |
|     setAllowsInvalid(false);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a MaskFormatter with the specified mask.
 | |
|    * @specnote doesn't actually throw a ParseException although it
 | |
|    * is declared to do so
 | |
|    * @param mask
 | |
|    * @throws java.text.ParseException
 | |
|    */
 | |
|   public MaskFormatter (String mask) throws java.text.ParseException
 | |
|   {
 | |
|     this();
 | |
|     setMask (mask);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the mask used in this MaskFormatter.
 | |
|    * @return the mask used in this MaskFormatter.
 | |
|    */
 | |
|   public String getMask()
 | |
|   {
 | |
|     return mask;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a String containing the characters that are not valid for input
 | |
|    * for this MaskFormatter.
 | |
|    * @return a String containing the invalid characters.
 | |
|    */
 | |
|   public String getInvalidCharacters()
 | |
|   {
 | |
|     return invalidChars;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets characters that are not valid for input. If
 | |
|    * <code>invalidCharacters</code> is non-null then no characters contained
 | |
|    * in it will be allowed to be input.
 | |
|    *
 | |
|    * @param invalidCharacters the String specifying invalid characters.
 | |
|    */
 | |
|   public void setInvalidCharacters (String invalidCharacters)
 | |
|   {
 | |
|     this.invalidChars = invalidCharacters;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a String containing the characters that are valid for input
 | |
|    * for this MaskFormatter.
 | |
|    * @return a String containing the valid characters.
 | |
|    */
 | |
|   public String getValidCharacters()
 | |
|   {
 | |
|     return validChars;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets characters that are valid for input. If
 | |
|    * <code>validCharacters</code> is non-null then no characters that are
 | |
|    * not contained in it will be allowed to be input.
 | |
|    *
 | |
|    * @param validCharacters the String specifying valid characters.
 | |
|    */
 | |
|   public void setValidCharacters (String validCharacters)
 | |
|   {
 | |
|     this.validChars = validCharacters;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the place holder String that is used in place of missing
 | |
|    * characters when the value doesn't completely fill in the spaces
 | |
|    * in the mask.
 | |
|    * @return the place holder String.
 | |
|    */
 | |
|   public String getPlaceholder()
 | |
|   {
 | |
|     return placeHolder;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the string to use if the value does not completely fill in the mask.
 | |
|    * If this is null, the place holder character will be used instead.
 | |
|    * @param placeholder the String to use if the value doesn't completely
 | |
|    * fill in the mask.
 | |
|    */
 | |
|   public void setPlaceholder (String placeholder)
 | |
|   {
 | |
|     this.placeHolder = placeholder;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the character used in place of missing characters when the
 | |
|    * value doesn't completely fill the mask.
 | |
|    * @return the place holder character
 | |
|    */
 | |
|   public char getPlaceholderCharacter()
 | |
|   {
 | |
|     return placeHolderChar;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the char  to use if the value does not completely fill in the mask.
 | |
|    * This is only used if the place holder String has not been set or does
 | |
|    * not completely fill in the mask.
 | |
|    * @param placeholder the char to use if the value doesn't completely
 | |
|    * fill in the mask.
 | |
|    */
 | |
|   public void setPlaceholderCharacter (char placeholder)
 | |
|   {
 | |
|     this.placeHolderChar = placeholder;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if stringToValue should return the literal
 | |
|    * characters in the mask.
 | |
|    * @return true if stringToValue should return the literal
 | |
|    * characters in the mask
 | |
|    */
 | |
|   public boolean getValueContainsLiteralCharacters()
 | |
|   {
 | |
|     return valueContainsLiteralCharacters;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Determines whether stringToValue will return literal characters or not.
 | |
|    * @param containsLiteralChars if true, stringToValue will return the
 | |
|    * literal characters in the mask, otherwise it will not.
 | |
|    */
 | |
|   public void setValueContainsLiteralCharacters (boolean containsLiteralChars)
 | |
|   {
 | |
|     this.valueContainsLiteralCharacters = containsLiteralChars;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the mask for this MaskFormatter.
 | |
|    * @specnote doesn't actually throw a ParseException even though it is
 | |
|    * declared to do so
 | |
|    * @param mask the new mask for this MaskFormatter
 | |
|    * @throws ParseException if <code>mask</code> is not valid.
 | |
|    */
 | |
|   public void setMask (String mask) throws ParseException
 | |
|   {
 | |
|     this.mask = mask;
 | |
| 
 | |
|     // Update the cached maskLength.
 | |
|     int end = mask.length() - 1;
 | |
|     maskLength = 0;
 | |
|     for (int i = 0; i <= end; i++)
 | |
|       {
 | |
|         // Handle escape characters properly - they don't add to the maskLength
 | |
|         // but 2 escape characters in a row is really one escape character and
 | |
|         // one literal single quote, so that does add 1 to the maskLength.
 | |
|         if (mask.charAt(i) == '\'')
 | |
|           {
 | |
|             // Escape characters at the end of the mask don't do anything.
 | |
|             if (i != end)
 | |
|               maskLength++;
 | |
|             i++;
 | |
|           }
 | |
|         else
 | |
|           maskLength++;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Installs this MaskFormatter on the JFormattedTextField.
 | |
|    * Invokes valueToString to convert the current value from the
 | |
|    * JFormattedTextField to a String, then installs the Actions from
 | |
|    * getActions, the DocumentFilter from getDocumentFilter, and the
 | |
|    * NavigationFilter from getNavigationFilter.
 | |
|    *
 | |
|    * If valueToString throws a ParseException, this method sets the text
 | |
|    * to an empty String and marks the JFormattedTextField as invalid.
 | |
|    */
 | |
|   public void install (JFormattedTextField ftf)
 | |
|   {
 | |
|     super.install(ftf);
 | |
|     if (ftf != null)
 | |
|       {
 | |
|         try
 | |
|         {
 | |
|           valueToString(ftf.getValue());
 | |
|         }
 | |
|         catch (ParseException pe)
 | |
|         {
 | |
|           // Set the text to an empty String and mark the JFormattedTextField
 | |
|           // as invalid.
 | |
|           ftf.setText("");
 | |
|           setEditValid(false);
 | |
|         }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Parses the text using the mask, valid characters, and invalid characters
 | |
|    * to determine the appropriate Object to return.  This strips the literal
 | |
|    * characters if necessary and invokes super.stringToValue.  If the paramter
 | |
|    * is invalid for the current mask and valid/invalid character sets this
 | |
|    * method will throw a ParseException.
 | |
|    *
 | |
|    * @param value the String to parse
 | |
|    * @throws ParseException if value doesn't match the mask and valid/invalid
 | |
|    * character sets
 | |
|    */
 | |
|   public Object stringToValue (String value) throws ParseException
 | |
|   {
 | |
|     return super.stringToValue(convertStringToValue(value));
 | |
|   }
 | |
| 
 | |
|   private String convertStringToValue(String value)
 | |
|     throws ParseException
 | |
|   {
 | |
|     CPStringBuilder result = new CPStringBuilder();
 | |
|     char valueChar;
 | |
|     boolean isPlaceHolder;
 | |
| 
 | |
|     int length = mask.length();
 | |
|     for (int i = 0, j = 0; j < length; j++)
 | |
|       {
 | |
|         char maskChar = mask.charAt(j);
 | |
| 
 | |
|         if (i < value.length())
 | |
|           {
 | |
|             isPlaceHolder = false;
 | |
|             valueChar = value.charAt(i);
 | |
|             if (maskChar != ESCAPE_CHAR && maskChar != valueChar)
 | |
|               {
 | |
|                 if (invalidChars != null
 | |
|                     && invalidChars.indexOf(valueChar) != -1)
 | |
|                   throw new ParseException("Invalid character: " + valueChar, i);
 | |
|                 if (validChars != null
 | |
|                     && validChars.indexOf(valueChar) == -1)
 | |
|                   throw new ParseException("Invalid character: " + valueChar, i);
 | |
|               }
 | |
|           }
 | |
|         else if (placeHolder != null && i < placeHolder.length())
 | |
|           {
 | |
|             isPlaceHolder = true;
 | |
|             valueChar = placeHolder.charAt(i);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             isPlaceHolder = true;
 | |
|             valueChar = placeHolderChar;
 | |
|           }
 | |
| 
 | |
|         // This switch block on the mask character checks that the character
 | |
|         // within <code>value</code> at that point is valid according to the
 | |
|         // mask and also converts to upper/lowercase as needed.
 | |
|         switch (maskChar)
 | |
|           {
 | |
|           case NUM_CHAR:
 | |
|             if (! Character.isDigit(valueChar))
 | |
|               throw new ParseException("Number expected: " + valueChar, i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case UPPERCASE_CHAR:
 | |
|             if (! Character.isLetter(valueChar))
 | |
|               throw new ParseException("Letter expected", i);
 | |
|             result.append(Character.toUpperCase(valueChar));
 | |
|             i++;
 | |
|             break;
 | |
|           case LOWERCASE_CHAR:
 | |
|             if (! Character.isLetter(valueChar))
 | |
|               throw new ParseException("Letter expected", i);
 | |
|             result.append(Character.toLowerCase(valueChar));
 | |
|             i++;
 | |
|             break;
 | |
|           case ALPHANUM_CHAR:
 | |
|             if (! Character.isLetterOrDigit(valueChar))
 | |
|               throw new ParseException("Letter or number expected", i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case LETTER_CHAR:
 | |
|             if (! Character.isLetter(valueChar))
 | |
|               throw new ParseException("Letter expected", i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case HEX_CHAR:
 | |
|             if (hexString.indexOf(valueChar) == -1 && ! isPlaceHolder)
 | |
|               throw new ParseException("Hexadecimal character expected", i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case ANYTHING_CHAR:
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case ESCAPE_CHAR:
 | |
|             // Escape character, check the next character to make sure that
 | |
|             // the literals match
 | |
|             j++;
 | |
|             if (j < length)
 | |
|               {
 | |
|                 maskChar = mask.charAt(j);
 | |
|                 if (! isPlaceHolder && getValueContainsLiteralCharacters()
 | |
|                     && valueChar != maskChar)
 | |
|                   throw new ParseException ("Invalid character: "+ valueChar, i);
 | |
|                 if (getValueContainsLiteralCharacters())
 | |
|                   {
 | |
|                     result.append(maskChar);
 | |
|                   }
 | |
|                 i++;
 | |
|               }
 | |
|             else if (! isPlaceHolder)
 | |
|               throw new ParseException("Bad match at trailing escape: ", i);
 | |
|             break;
 | |
|           default:
 | |
|             if (! isPlaceHolder && getValueContainsLiteralCharacters()
 | |
|                 && valueChar != maskChar)
 | |
|               throw new ParseException ("Invalid character: "+ valueChar, i);
 | |
|             if (getValueContainsLiteralCharacters())
 | |
|               {
 | |
|                 result.append(maskChar);
 | |
|               }
 | |
|             i++;
 | |
|           }
 | |
|       }
 | |
|     return result.toString();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a String representation of the Object value based on the mask.
 | |
|    *
 | |
|    * @param value the value to convert
 | |
|    * @throws ParseException if value is invalid for this mask and valid/invalid
 | |
|    * character sets
 | |
|    */
 | |
|   public String valueToString(Object value) throws ParseException
 | |
|   {
 | |
|     String string = value != null ? value.toString() : "";
 | |
|     return convertValueToString(string);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method takes in a String and runs it through the mask to make
 | |
|    * sure that it is valid.  If <code>convert</code> is true, it also
 | |
|    * converts letters to upper/lowercase as required by the mask.
 | |
|    * @param value the String to convert
 | |
|    * @return the converted String
 | |
|    * @throws ParseException if the given String isn't valid for the mask
 | |
|    */
 | |
|   private String convertValueToString(String value)
 | |
|     throws ParseException
 | |
|   {
 | |
|     CPStringBuilder result = new CPStringBuilder();
 | |
|     char valueChar;
 | |
|     boolean isPlaceHolder;
 | |
| 
 | |
|     int length = mask.length();
 | |
|     for (int i = 0, j = 0; j < length; j++)
 | |
|       {
 | |
|         char maskChar = mask.charAt(j);
 | |
|         if (i < value.length())
 | |
|           {
 | |
|             isPlaceHolder = false;
 | |
|             valueChar = value.charAt(i);
 | |
|             if (maskChar != ESCAPE_CHAR && valueChar != maskChar)
 | |
|               {
 | |
|                 if (invalidChars != null
 | |
|                     && invalidChars.indexOf(valueChar) != -1)
 | |
|                   throw new ParseException("Invalid character: " + valueChar,
 | |
|                                            i);
 | |
|                 if (validChars != null && validChars.indexOf(valueChar) == -1)
 | |
|                   throw new ParseException("Invalid character: " + valueChar +" maskChar: " + maskChar,
 | |
|                                            i);
 | |
|               }
 | |
|           }
 | |
|         else if (placeHolder != null && i < placeHolder.length())
 | |
|           {
 | |
|             isPlaceHolder = true;
 | |
|             valueChar = placeHolder.charAt(i);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             isPlaceHolder = true;
 | |
|             valueChar = placeHolderChar;
 | |
|           }
 | |
| 
 | |
|         // This switch block on the mask character checks that the character
 | |
|         // within <code>value</code> at that point is valid according to the
 | |
|         // mask and also converts to upper/lowercase as needed.
 | |
|         switch (maskChar)
 | |
|           {
 | |
|           case NUM_CHAR:
 | |
|             if ( ! isPlaceHolder && ! Character.isDigit(valueChar))
 | |
|               throw new ParseException("Number expected: " + valueChar, i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case UPPERCASE_CHAR:
 | |
|             if (! Character.isLetter(valueChar))
 | |
|               throw new ParseException("Letter expected", i);
 | |
|             result.append(Character.toUpperCase(valueChar));
 | |
|             i++;
 | |
|             break;
 | |
|           case LOWERCASE_CHAR:
 | |
|             if (! Character.isLetter(valueChar))
 | |
|               throw new ParseException("Letter expected", i);
 | |
|             result.append(Character.toLowerCase(valueChar));
 | |
|             i++;
 | |
|             break;
 | |
|           case ALPHANUM_CHAR:
 | |
|             if (! Character.isLetterOrDigit(valueChar))
 | |
|               throw new ParseException("Letter or number expected", i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case LETTER_CHAR:
 | |
|             if (! Character.isLetter(valueChar))
 | |
|               throw new ParseException("Letter expected", i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case HEX_CHAR:
 | |
|             if (hexString.indexOf(valueChar) == -1 && ! isPlaceHolder)
 | |
|               throw new ParseException("Hexadecimal character expected", i);
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case ANYTHING_CHAR:
 | |
|             result.append(valueChar);
 | |
|             i++;
 | |
|             break;
 | |
|           case ESCAPE_CHAR:
 | |
|             // Escape character, check the next character to make sure that
 | |
|             // the literals match
 | |
|             j++;
 | |
|             if (j < length)
 | |
|               {
 | |
|                 maskChar = mask.charAt(j);
 | |
|                 if (! isPlaceHolder && getValueContainsLiteralCharacters()
 | |
|                     && valueChar != maskChar)
 | |
|                   throw new ParseException ("Invalid character: "+ valueChar, i);
 | |
|                 if (getValueContainsLiteralCharacters())
 | |
|                   i++;
 | |
|                 result.append(maskChar);
 | |
|               }
 | |
|             break;
 | |
|           default:
 | |
|             if (! isPlaceHolder && getValueContainsLiteralCharacters()
 | |
|                 && valueChar != maskChar)
 | |
|               throw new ParseException ("Invalid character: "+ valueChar, i);
 | |
|             if (getValueContainsLiteralCharacters())
 | |
|               i++;
 | |
|             result.append(maskChar);
 | |
|           }
 | |
|       }
 | |
|     return result.toString();
 | |
|   }
 | |
| 
 | |
| }
 |