/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Blacksmith, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.ui.swing.components; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.KeyEvent; import javax.swing.JPasswordField; /** * SmartPasswordField is an extention of JPasswordField. It does everything a * JPassword does, as well as limit the number of characters. The user of this * class can specify that a password can only have a maximum of 10 characters * for instance. * * @author rob@straylight.princeton.com * @author $Author: cgruber $ * @version $Revision: 904 $ */ public class SmartPasswordField extends JPasswordField { /******************************* * CONSTANTS *******************************/ private static final int BACKSPACE = 8; private static final int DELETE = 127; private static final int SPACE = 32; private static final int DASH = 45; private static final int UNDERSCORE = 95; private static final int PERIOD = 46; private static final int PASTE = 22; // Ctl-V private int passwordLength = Integer.MAX_VALUE; /******************************* * PUBLIC METHODS *******************************/ /** * Default constructor. */ public SmartPasswordField() { super(); } /** * This constructor allows the user to set the maximum length of the password. * * @param aLength The maximum length of the password. */ public SmartPasswordField(int aLength) { this(); setPasswordLength(aLength); } /** * Sets the maximum lenght of the password. The value must be 0 or greater. If * the length specified is less than 0, then no action occurs. * * @param aLength The maximum lenght of the password. */ public void setPasswordLength(int aLength) { if (aLength >= 0) { passwordLength = aLength; } } /** * Returns the current maximum length of the password. * * @return The current maximum length of the password. */ public int getPasswordLength() { return passwordLength; } /** * This method processes a key event. This event is generated by input from the * keyboard when this text field has the focus. This method is called for every * key that is pressed and released on the keyboard. This includes modifier keys * like the shift and alt keys. This class looks at the key and determines if * the key is valid input given the restrictions of this class.
*
* * @param e A key event generated by a keyboard action. */ public void processKeyEvent(KeyEvent e) { String currentText = ""; String testString = ""; char newChar = e.getKeyChar(); int currentLength = 0; int selectionStart = 0; int selectionEnd = 0; int endOfHead = 0; int startOfTail = 0; boolean backspace = false; boolean delete = false; boolean paste = false; boolean insertionPoint = false; boolean selectionAtStart = false; boolean selectionAtEnd = false; backspace = (newChar == BACKSPACE); delete = (newChar == DELETE); paste = (newChar == PASTE); if ((e.getKeyCode() == KeyEvent.VK_UNDEFINED) || ((backspace) || (delete) || (paste))) // A "key-typed" event { if (isValidCharacter(newChar)) { if ((isPrintableCharacter(newChar)) || (backspace) || (delete) || (paste)) { // Analyze the current contents of the field currentText = new String(getPassword()); currentLength = currentText.length(); selectionStart = getSelectionStart(); selectionEnd = getSelectionEnd(); insertionPoint = (selectionStart == selectionEnd); selectionAtStart = (selectionStart == 0); selectionAtEnd = (selectionEnd >= currentLength); if (selectionEnd > currentLength) { setSelectionEnd(currentLength); } // Generate new string if (selectionStart > 0) // Create head of test string { endOfHead = selectionStart; if (insertionPoint && backspace) { endOfHead -= 1; } testString += currentText.substring(0, endOfHead); } if (!(backspace || delete || paste)) // Add the new character { testString += newChar; } if (paste) // Add the string from the clipboard { Transferable data = getToolkit().getSystemClipboard().getContents(this); if (data != null) { try { String clipString = (String) data.getTransferData(DataFlavor.stringFlavor); testString += clipString; } catch (java.io.IOException ioe) { // Do nothing } catch (UnsupportedFlavorException ufe) { // Do nothing } } } if (selectionEnd < currentLength) // Add the tail of the string { startOfTail = selectionEnd; if (insertionPoint && delete) { startOfTail += 1; } testString += currentText.substring(startOfTail); } } if (testString.compareTo("") != 0) // Null string is OK { if (!(isValidString(testString))) { e.consume(); } } } else { e.consume(); } } super.processKeyEvent(e); postProcessing(); } /******************************* * PROTECTED METHODS *******************************/ /** * Returns whether the inputted character is valid or not. In this case all * characters are valid input. * * @param aChar A character to perform the validity test with. * @return True if the character is valid for this subclassed text field.
* False is the character is not valid. */ protected boolean isValidCharacter(char aChar) { return true; } /** * Returns whether a string is valid for this text field. As the user types from * the keyboard, this method is called to determine if the new string in the * text field is valid based upon the restriction of this class. The length of * the new string is checked against the maximum password length. * * @param aString The string to perform the validity check with. * @return True if the length of the string is less than or equal to the maximum * length. False if the character is not valud. */ protected boolean isValidString(String aString) { if (aString.length() > passwordLength) { return false; } return true; } /** * This class does not need any post processing. */ protected void postProcessing() { /* Do Nothing */ } /******************************* * PRIVATE METHODS *******************************/ private boolean isPrintableCharacter(char inputChar) { if ((inputChar >= ' ') && (inputChar <= '~')) { return true; } return false; } }