Coverage Report - net.wotonomy.ui.swing.components.SmartTextField
 
Classes in this File Line Coverage Branch Coverage Complexity
SmartTextField
0% 
0% 
3.833
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Blacksmith, Inc.
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.ui.swing.components;
 20  
 
 21  
 import java.awt.datatransfer.DataFlavor;
 22  
 import java.awt.datatransfer.Transferable;
 23  
 import java.awt.datatransfer.UnsupportedFlavorException;
 24  
 import java.awt.event.KeyEvent;
 25  
 
 26  
 import javax.swing.JTextField;
 27  
 
 28  
 /**
 29  
  * SmartTextField is an abstract class for that allows the text field to
 30  
  * intelligently analyze the user's input in real-time.  As the user enters
 31  
  * keystrokes, the generated string is analyzed to determine if the new string
 32  
  * is valid based on the criteria of the concrete classes that extend this
 33  
  * class.  An invalid keystroke is rejected and not displayed in the text
 34  
  * field.  This class can be extended to to create smart text fields that only
 35  
  * accept integers or floating points number or alphabetic strings of maximum
 36  
  * length.  These are several examples.
 37  
  *
 38  
  * @author rob@straylight.princeton.com
 39  
  * @author $Author: cgruber $
 40  
  * @version $Revision: 904 $
 41  
  */
 42  
 public abstract class SmartTextField extends JTextField
 43  
 {
 44  
 
 45  
 /*******************************
 46  
 * CONSTANTS
 47  
 *******************************/
 48  
    private static final int BACKSPACE = 8;
 49  
    private static final int DELETE = 127;
 50  
    private static final int SPACE = 32;
 51  
    private static final int DASH = 45;
 52  
    private static final int UNDERSCORE = 95;
 53  
    private static final int PERIOD = 46;
 54  
    private static final int PASTE = 22;  // Ctl-V
 55  
 
 56  
    
 57  
 /*******************************
 58  
 * PUBLIC METHODS
 59  
 *******************************/
 60  
 
 61  
 /**
 62  
 * This method processes a key event.  This event is generated by input from the
 63  
 * keyboard when this text field has the focus.  This method is called for every
 64  
 * key that is pressed and released on the keyboard.  This includes modifier
 65  
 * keys like the shift and alt keys.  This class looks at the key and determines
 66  
 * if the key is valid input given the restrictions of the concrete sub-classes. <BR> <BR>
 67  
 * Example - A smart text field only allows alphabetic characters.  If the key
 68  
 * pressed is a "2" then this method will determine that the key is invalid and
 69  
 * "consume" the key event. <BR> <BR>
 70  
 * Note - Every printable character has a "TYPED" key event.  Currentlt under
 71  
 * Java 1.2.1 this does not happen.  Bug 4186905 relating this bug has been
 72  
 * fixed and is awaiting release.
 73  
 * @param e A key event generated by a keyboard action.
 74  
 */
 75  
    public void processKeyEvent(KeyEvent e)
 76  
    {
 77  0
       String currentText = "";
 78  0
       String testString = "";
 79  0
       char newChar = e.getKeyChar();
 80  0
       int currentLength = 0;
 81  0
       int selectionStart = 0;
 82  0
       int selectionEnd = 0;
 83  0
       int endOfHead = 0;
 84  0
       int startOfTail = 0;
 85  0
       boolean backspace = false;
 86  0
       boolean delete = false;
 87  0
       boolean paste = false;
 88  0
       boolean insertionPoint = false;
 89  0
       boolean selectionAtStart = false;
 90  0
       boolean selectionAtEnd = false;
 91  
 
 92  0
       backspace = (newChar == BACKSPACE);
 93  0
       delete = (newChar == DELETE);
 94  0
       paste = (newChar == PASTE);
 95  
 
 96  0
       if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste)))  // A "key-typed" event
 97  
       {
 98  0
          if (isValidCharacter(newChar))
 99  
          {
 100  
 
 101  0
             if ((isPrintableCharacter(newChar)) || (backspace) || (delete) || (paste))
 102  
             {
 103  
                // Analyze the current contents of the field
 104  0
                currentText = getText();
 105  0
                currentLength = currentText.length();
 106  
 
 107  0
                selectionStart = getSelectionStart();
 108  0
                selectionEnd = getSelectionEnd();
 109  
 
 110  0
                insertionPoint = (selectionStart == selectionEnd);
 111  0
                selectionAtStart = (selectionStart == 0);
 112  0
                selectionAtEnd = (selectionEnd >= currentLength);
 113  0
                if (selectionEnd > currentLength)
 114  
                {
 115  0
                   setSelectionEnd(currentLength);
 116  
                }
 117  
 
 118  
                // Generate new string
 119  0
                if (selectionStart > 0) // Create head of test string
 120  
                {
 121  0
                   endOfHead = selectionStart;
 122  0
                   if (insertionPoint && backspace)
 123  
                   {
 124  0
                      endOfHead -= 1;
 125  
                   }
 126  0
                   testString += currentText.substring(0, endOfHead);
 127  
                }
 128  
 
 129  0
                if (!(backspace || delete || paste))  // Add the new character
 130  
                {
 131  0
                   testString += newChar;
 132  
                }
 133  
 
 134  0
                if (paste)  // Add the string from the clipboard
 135  
                {
 136  0
                   Transferable data = getToolkit().getSystemClipboard().getContents(this);
 137  0
                   if (data != null)
 138  
                   {
 139  
                      try
 140  
                      {
 141  0
                         String clipString = (String)data.getTransferData(DataFlavor.stringFlavor);
 142  0
                         testString += clipString;
 143  
                      }
 144  0
                      catch (java.io.IOException ioe)
 145  
                      {
 146  
                         // Do nothing
 147  
                      }
 148  0
                      catch (UnsupportedFlavorException ufe)
 149  
                      {
 150  
                         // Do nothing
 151  0
                      }
 152  
                   }
 153  
                }
 154  
 
 155  0
                if (selectionEnd < currentLength) // Add the tail of the string
 156  
                {
 157  0
                   startOfTail = selectionEnd;
 158  0
                   if (insertionPoint && delete)
 159  
                   {
 160  0
                      startOfTail += 1;
 161  
                   }
 162  0
                   testString += currentText.substring(startOfTail);
 163  
                }
 164  
 
 165  
             }
 166  
 
 167  0
             if (testString.compareTo("") != 0)  // Null string is OK
 168  
             {
 169  0
                if (!(isValidString(testString)))
 170  
                {
 171  0
                   e.consume();
 172  0
                }
 173  
             }
 174  
          }
 175  
          else
 176  
          {
 177  0
             e.consume();
 178  
          }
 179  
       }
 180  0
       super.processKeyEvent(e);
 181  
 
 182  0
       postProcessing();
 183  0
    }
 184  
 
 185  
 
 186  
 /*******************************
 187  
 * PROTECTED METHODS
 188  
 *******************************/
 189  
 
 190  
 /**
 191  
 * Default constructor for this class.  The initial text of the smart text field
 192  
 * can be specified as well as the size (in characters) of the text field.
 193  
 * @param text The initial string that is displayed in the text field.
 194  
 * @param columns THe width of the text field in characters.
 195  
 */
 196  
    protected SmartTextField(String text, int columns)
 197  
    {
 198  0
       super(text, columns);
 199  0
    }
 200  
 
 201  
 /**
 202  
 * Returns whether a character is valid for this text field.  As the user types
 203  
 * from the keyboard, this method is called to determine if the character is a
 204  
 * valid character based in the restrictions of the subclass.
 205  
 * @param aChar A character to perform the validity test with.
 206  
 * @return True if the character is valid for this subclassed text field. <BR>
 207  
 *         False is the character is not valid.
 208  
 */
 209  
    abstract protected boolean isValidCharacter(char aChar);
 210  
 
 211  
 /**
 212  
 * Returns whether a string is valid for this text field.  As the user types from
 213  
 * the keyboard, this method is called to determine if the new string in the text
 214  
 * field is valid based upon the restriction of the subclass.  This is done after
 215  
 * the character has been determined to be valid since there can be restrictions
 216  
 * placed on the text string as a whole, such a maximum length or date format.
 217  
 * @param aString The string to perform the validity check with.
 218  
 * @return True if the string is valid for this subclassed text field. <BR>
 219  
 *         False if the character is not valud.
 220  
 */
 221  
    abstract protected boolean isValidString(String aString);
 222  
 
 223  
 /**
 224  
 * This method is used by the any subclass that need to complete any processing
 225  
 * of the text string in the text field after all the requirement checks have
 226  
 * been performed.
 227  
 */
 228  
    abstract protected void postProcessing();
 229  
 
 230  
 
 231  
 /*******************************
 232  
 * PRIVATE METHODS
 233  
 *******************************/
 234  
 
 235  
    private boolean isPrintableCharacter(char inputChar)
 236  
    {
 237  0
       if ((inputChar >= ' ') && (inputChar <= '~'))
 238  
       {
 239  0
          return true;
 240  
       }
 241  0
       return false;
 242  
    }
 243  
 
 244  
 }