home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
VCAFE.3.0A
/
Main.bin
/
FormattedTextField.java
< prev
next >
Wrap
Text File
|
1998-10-19
|
37KB
|
1,192 lines
package symantec.itools.awt;
import java.awt.Toolkit;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.TextField;
import java.awt.event.*;
// 05/29/97 RKM Convert to 1.1 event model
// Deprecated getter for booleans, and added is
// Used add/removeNotify to listen to events
// WARNING: Could not test component due bug in MRJ,
// doesn't work InputEvent.consume()
// 05/14/97 TNM If there is not mask it works like java.awt.TextField
// 01/29/97 TWB Integrated changes from Windows
// 07/30/97 CAR inner adaptor class implements java.io.Serializable
// 08/26/97 CAR changed keyPressed to call processchar with getKeyChar instead of getKeyCode
// 10/09/97 LAB Re-wrote processChar. This fixes many issues with this component. Modified
// several functions, and added several, in this process. These modifications
// address Mac bug #3383, #7636, #7638 and #8517. !!! LAB !!! Note, processChar
// is by no means optimized; this should be done at a later date. Deprecated
// setEditFont and getEditFont. Removed overriden setFont.
// 10/11/97 LAB Removed unnecessary items related to overriden editable. Handle empty
// string masks correctly now (Addresses Mac Bug #9198). Fixed problems
// between setText and setMask confusing the unformattedCurrent string and
// Re-wrote applyMask to correctly update the unformattedCurrent string
// (Addresses Mac Bugs #9199, #9168, and #9167). Moved filtering code
// into filterChar to unify applyMask and applyMaskToChar. Added
// getFormattedText to return the contents of the text field, since
// getText now returns the unformatted string.
// 18/2/98 fbeninc cheched for \0 sent with shift key.line790/1006
// 10/6/98 MSH Bug fix 65516, fixed shift key moving cursor back one position
/**
* Creates a box in which the user can type text. Text formatting logic is
* applied to the user input.
* <p>
* Use FormattedTextField to
* <UL>
* <DT>╖ Limit the type of text that can be entered in the text box.</DT>
* <DT>╖ Display text captured from the keyboard.</DT>
* <DT>╖ Edit a line of text.</DT>
* <DT>╖ Post an event based on text input from the keyboard.</DT>
* </UL>
* If the text box already contains text, the user can select the default text
* and delete or edit it.
* <p>
* @version 1.1, August 30, 1997
* @author Symantec
*/
public class FormattedTextField extends TextField
{
/**
* Character mask constant, the character following this ESCAPE will be placed into input string.
*/
public final char ESCAPE = '/';
/**
* Character mask constant, input must be a digit character.
*/
public final char DIGIT = '9';
/**
* Character mask constant, input must be a sign (+ or -) character.
*/
public final char SIGN = '+';
/**
* Character mask constant, input must be a digit or sign (+ or -) character.
*/
public final char DIGIT_OR_SIGN = '-';
/**
* Character mask constant, input must be an uppercase alpha character.
*/
public final char ALPHA_UPPER = 'A';
/**
* Character mask constant, input must be a lowercase alpha character.
*/
public final char ALPHA_LOWER = 'a';
/**
* Character mask constant, input must be an alpha character (it will be converted to uppercase).
*/
public final char ALPHA_TO_UPPER = 'U';
/**
* Character mask constant, input must be an alpha character (it will be converted to lowercase).
*/
public final char ALPHA_TO_LOWER = 'L';
/**
* Character mask constant, input must be a digit or an uppercase alpha character.
*/
public final char ALPHANUMERIC_UPPER = 'X';
/**
* Character mask constant, input must be a digit or a lowercase alpha character.
*/
public final char ALPHANUMERIC_LOWER = 'x';
/**
* Character mask constant, input must be a digit or alpha character (it will be converted to uppercase).
*/
public final char ALPHANUMERIC_TO_UPPER = 'N';
/**
* Character mask constant, input must be a digit or alpha character (it will be converted to lowercase).
*/
public final char ALPHANUMERIC_TO_LOWER = 'n';
/**
* Character mask constant, input can be any character.
*/
public final char ANY = '*';
/**
* Constructs a new FormattedTextField. It can have 256 columns.
*/
public FormattedTextField()
{
this(256);
}
/**
* Constructs a new FormattedTextField with the specified number of columns.
* @param i the number of character columns
*/
public FormattedTextField(int i)
{
this("", i);
}
/**
* Constructs a new FormattedTextField containing the specified text.
* It can have 256 columns.
* @param s the field text
*/
public FormattedTextField(String s)
{
this(s, 256);
}
/**
* Constructs a new FormattedTextField containing the specified text and
* able to have the specified number of columns.
* @param s the field text
* @param i the number of character columns
*/
public FormattedTextField(String s, int i)
{
super(s, i);
caret = 0;
unformattedCurrent = "";
designTimeText = "";
}
/**
* Sets the valid string format mask for this field.
* @param mask the new valid string format mask
* @see #getMask
*/
public void setMask(String mask)
{
if(mask != null && mask.length() < 1)
{
this.mask = null;
}
else
{
this.mask = mask;
}
maskStripEscapes = stripMaskEscapes();
maskStripEscapesLen = maskStripEscapes.length();
//Apply the new mask to our current text.
setText(getText());
}
/**
* Gets the current valid string format mask.
* @return the string that defines valid input into this field.
* @see #setMask
*/
public String getMask()
{
return mask;
}
/**
* @deprecated
*/
public void setEditFont(Font f)
{
setFont(f);
}
/**
* @deprecated
*/
public Font getEditFont()
{
return getFont();
}
/**
* Sets the text of this TextComponent to the specified text
* after passing the specified text throught the filter.
* @param t the new text to be set
* @see #getText
*/
public void setText(String t)
{
//Keep the original string around at design time to return from getText.
if(java.beans.Beans.isDesignTime())
designTimeText = t;
String newString;
if(mask == null)
{
newString = t;
unformattedCurrent = newString;
}
else
{
newString = applyMask(t);
}
super.setText(newString);
}
/**
* Gets the unformatted string of filtered characters.
* @return the string of unformatted characters that were accepted by
* the mask filtering process. At design time this returns the text passed
* to setText.
* @see #setText
* @see #getFormattedText
*/
public String getText()
{
if(java.beans.Beans.isDesignTime())
return designTimeText;
else
return unformattedCurrent;
}
/**
* Gets the displayed contents of the component.
* @return the string currently displayed by the component.
* @see #setText
* @see #getText
*/
public String getFormattedText()
{
return super.getText();
}
/**
* Sets whether the text field is editable.
* @param f true if the text field is editable, false otherwise
* @see java.awt.TextComponent#isEditable
*/
public void setEditable(boolean f)
{
super.setEditable(f);
setEnabled(f);
}
/**
* Returns a string defining an input template. The mask ESCAPE
* characters will be place in the string. All other mask characters will
* have spaces in place of them. For example, a mask of "99/-9/-9" results
* in a string set to " - - ".
* @return the template string defined by the mask, with spaces as placeholders.
*/
public String getMaskTemplateString()
{
String newString = "";
if(mask != null)
{
int ml = mask.length();
int maskIndex;
char maskChar;
for (maskIndex = 0; maskIndex < ml; maskIndex++)
{
maskChar = mask.charAt(maskIndex);
newString += maskChar == ESCAPE ? mask.charAt(++maskIndex) : ' ';
}
}
return newString;
}
/**
* Clears the contents of the field and sets the text field's contents to
* be an input template. The mask ESCAPE characters will be place in the
* field. All other mask characters will have spaces in place of them.
* For example, a mask of "99/-9/-9" results in the text field getting
* set to " - - ".
*/
public void setFillMask()
{
String newString = getMaskTemplateString();
unformattedCurrent = "";
super.setText(newString);
}
/**
* Tells this component that it has been added to a container.
* This is a standard Java AWT method which gets called by the AWT when
* this component is added to a container. Typically, it is used to
* create this component's peer.
*
* It has been overridden here to call addKeyListener.
*
* @see #removeNotify
*/
public synchronized void addNotify()
{
if (keyListener == null)
{
keyListener = new Key();
addKeyListener(keyListener);
}
super.addNotify();
}
/**
* Tells this component that it is being removed from a container.
* This is a standard Java AWT method which gets called by the AWT when
* this component is removed from a container. Typically, it is used to
* destroy the peers of this component and all its subcomponents.
*
* It has been overridden here to call removeKeyListener.
*
* @see #addNotify
*/
public synchronized void removeNotify()
{
if (keyListener != null)
{
removeKeyListener(keyListener);
keyListener = null;
}
super.removeNotify();
}
/**
* @deprecated As of JDK version 1.1,
* replaced by getPreferredSize().
*/
public Dimension preferredSize() {
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(f);
if (mask != null) {
int w = fm.stringWidth("W") * maskStripEscapesLen + 4;
int h = fm.getHeight() + 4;
return new Dimension(w, h);
}
else {
return new Dimension(fm.stringWidth("ABCDE") + 4, fm.getHeight() + 4);
}
}
return new Dimension(30, 15);
}
/**
* Returns the recommended dimensions to properly display this component.
* This is a standard Java AWT method which gets called to determine
* the recommended size of this component.
*
* @see #getMinimumSize
*/
public Dimension getPreferredSize() {
return preferredSize();
}
/**
* @deprecated As of JDK version 1.1,
* replaced by getMinimumSize().
*/
public Dimension minimumSize() {
return preferredSize();
}
/**
* Returns the minimum dimensions to properly display this component.
* This is a standard Java AWT method which gets called to determine
* the minimum size of this component.
*
* @see #getPreferredSize
*/
public Dimension getMinimumSize() {
return minimumSize();
}
/**
* Processes KEY_PRESS and KEY_ACTION events.
* This is a standard Java AWT method which gets called by the AWT
* method handleEvent() in response to receiving a KEY_PRESS or
* KEY_ACTION event. These events occur when this component has the focus
* and the user presses a "normal" or an "action" (F1, page up, etc) key.
*
* @param evt the Event
* @param key the key that was pressed
* @return true if the event was handled
* @see java.awt.Component#keyUp
* @see java.awt.Component#handleEvent
*/
class Key extends KeyAdapter implements java.io.Serializable
{
public void keyTyped(KeyEvent e)
{
e.consume();
processChar(e.getKeyChar());
}
/**
* Invoked when a key has been pressed.
*/
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
// System.out.println( "KeyAdapter- key: " + key );
switch (key)
{
case KeyEvent.VK_LEFT:
{
if (--caret < 0)
caret = 0;
break;
}
case KeyEvent.VK_RIGHT:
{
if (++caret >= maskStripEscapesLen)
caret = maskStripEscapesLen;
break;
}
case KeyEvent.VK_HOME:
{
caret = 0;
break;
}
case KeyEvent.VK_END:
{
caret = maskStripEscapesLen;
break;
}
case KeyEvent.VK_ENTER:
case KeyEvent.VK_TAB:
case KeyEvent.VK_SHIFT:
{
//Do nothing
break;
}
// handle VK_BACK_SPACE with keyTyped
case KeyEvent.VK_DELETE:
{
e.consume();
processChar(e.getKeyChar());
break;
}
default:
{
e.consume();
break;
}
}
}
}
/**
* Returns the next valid character in the input string.
* @param s the input string
* @param start the zero-relative index of the first character to check in
* the input string
* @param maskChar the mask character used to determine which input characters
* are valid
*/
protected int validChar(String s, int start, char maskChar)
{
boolean isReturn;
int len = s.length();
for (int i = start; i < len; ++i)
{
isReturn = false;
char c = s.charAt(i);
switch (maskChar)
{
case DIGIT :
if (Character.isDigit(c))
isReturn = true;
break;
case SIGN :
if (c == '+' || c == '-')
isReturn = true;
break;
case DIGIT_OR_SIGN :
if (Character.isDigit(c) || c == '+' || c == '-')
isReturn = true;
break;
case ALPHA_UPPER :
if (Character.isUpperCase(c))
isReturn = true;
break;
case ALPHA_LOWER :
if (Character.isLowerCase(c))
isReturn = true;
break;
case ALPHANUMERIC_UPPER :
if (Character.isUpperCase(c) || Character.isDigit(c))
isReturn = true;
break;
case ALPHANUMERIC_LOWER :
if (Character.isLowerCase(c) || Character.isDigit(c))
isReturn = true;
break;
case ALPHA_TO_UPPER :
if (Character.isUpperCase(c) || Character.isLowerCase(c))
isReturn = true;
break;
case ALPHA_TO_LOWER :
if (Character.isUpperCase(c) || Character.isLowerCase(c))
isReturn = true;
break;
case ALPHANUMERIC_TO_UPPER :
if (Character.isUpperCase(c) || Character.isLowerCase(c) || Character.isDigit(c))
isReturn = true;
break;
case ALPHANUMERIC_TO_LOWER :
if (Character.isUpperCase(c) || Character.isLowerCase(c) || Character.isDigit(c))
isReturn = true;
break;
case ANY :
isReturn = true;
break;
}
if(isReturn)
return i;
}
return -1;
}
/**
* Returns a formatted string, given an input string and the current valid
* string format mask.
* @param s the input string
* @return the input string formatted using the current valid string
* format mask.
*/
protected String applyMask(String s)
{
//If there is no mask, there is no formatting needed.
if(mask == null)
{
unformattedCurrent = s;
return s;
}
//Reset the unformatted string
unformattedCurrent = "";
int maskLength = mask.length();
int stringLength = s == null ? 0 : s.length();
char maskChar;
char stringChar;
String newString = "";
boolean isValidChar;
int maskIndex = 0;
int stringIndex = 0;
while(stringIndex < stringLength && maskIndex < maskLength)
{
maskChar = mask.charAt(maskIndex);
//If the maskChar is a escape sequence initiator, add the next character to the display string.
if(maskChar == ESCAPE)
{
++maskIndex;
if(maskIndex < maskLength)
newString += mask.charAt(maskIndex);
++maskIndex;
}
else
{
stringChar = s.charAt(stringIndex);
isValidChar = validChar("" + stringChar, 0, maskChar) != -1 ? true : false;
//If the character is valid at the index, as defined by the maskChar...
if(isValidChar)
{
//Apply any transformations needed to the character.
stringChar = filterChar(stringChar, maskChar);
//Add the character to the string to display.
newString += stringChar;
//Add the character to the unformatted string to keep track of characters that
//were accepted, and not part of the mask.
unformattedCurrent += stringChar;
++maskIndex;
}
++stringIndex;
}
}
//If the string didn't fill the entire mask, then pad the display string with the mask template
int newLength = newString.length();
if(newLength < maskStripEscapesLen)
{
String maskTemplate = getMaskTemplateString();
newString += maskTemplate.substring(newLength > 0 ? newLength - 1 : 0);
}
return newString;
}
/**
* Apply the mask at index to the given character.
* @param char targetChar the character to apply the mask to.
* @param int index the index in the mask to use on the given character.
* @return A string with the given character with the mask
* at the given index applied. An empty string if the character was
* invalid or if the given index was an escape character index.
*/
protected String applyMaskToChar(char targetChar, int index)
{
if(mask == null)
return ("" + targetChar);
if (isEscape(index))
{
return "";
}
else
{
//Count the number of escape characters before the index so we have a valid index into the mask
int numEscapes = 0;
for(int i = 0; i < index; ++i)
{
if(isEscape(i))
numEscapes++;
}
char maskChar = mask.charAt(index + numEscapes);
boolean isValidChar = validChar("" + targetChar, 0, maskChar) != -1 ? true : false;
if(isValidChar)
{
targetChar = filterChar(targetChar, maskChar);
return (String.valueOf(targetChar));
}
else
{
return "";
}
}
}
/**
* Filters the given target character with the given mask character
* @param char targetChar the character to apply the filter to.
* @param char maskChar the character to use as a filter. Should match
* one of the pre-defined types.
* @see #applyMask
* @see #applyMaskToChar
* @see #ALPHA_TO_UPPER
* @see #ALPHA_TO_LOWER
* @see #ALPHANUMERIC_TO_UPPER
* @see #ALPHANUMERIC_TO_LOWER
*/
protected char filterChar(char targetChar, char maskChar)
{
char returnChar = targetChar;
switch (maskChar)
{
case ALPHA_TO_UPPER:
if (Character.isLowerCase(targetChar))
returnChar = Character.toUpperCase(targetChar);
break;
case ALPHA_TO_LOWER:
if (Character.isUpperCase(targetChar))
returnChar = Character.toLowerCase(targetChar);
break;
case ALPHANUMERIC_TO_UPPER:
if (Character.isLowerCase(targetChar))
returnChar = Character.toUpperCase(targetChar);
break;
case ALPHANUMERIC_TO_LOWER:
if (Character.isUpperCase(targetChar))
returnChar = Character.toLowerCase(targetChar);
break;
}
return returnChar;
}
/**
* Strips escape characters from the given string.
* For example, a mask of "99/-9/-9" and an input string of "12-3-4"
* results in "1234".
* @param s the input string
* @return the input string stripped of mask escape characters.
*/
protected String stripMask(String s)
{
int sl = s.length();
int i = 0;
String newString = "";
while (i < maskStripEscapesLen && i < sl)
{
if (isEscape(i))
++i;
else
newString += s.charAt(i++);
}
return newString;
}
/**
* Handles KEY_PRESS processing.
* @param int the key that was pressed
*/
protected void processChar(int key)
{
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
boolean isSelection = (selStart != selEnd);
boolean isBackspace = (key == BACKSPACE);
boolean isDelete = (key == DEL);
String keyString = isBackspace || isDelete ? "" : String.valueOf((char)key);
String currentString = getFormattedText();
int currentLength = currentString.length();
String leftOfSelection = selStart > 0 ? currentString.substring(0, selStart) : "";
String rightOfSelection = selEnd < currentLength ? currentString.substring(selEnd) : "";
String finalString = "";
//Set the default position of the caret to be the beginning of the selection.
caret = selStart;
//If we have no mask to worry about
if(mask == null)
{
//If we need to erase something
if(isBackspace || isDelete)
{
if(isSelection)
{
finalString = leftOfSelection + rightOfSelection;
}
else
{
if(isBackspace)
{
String tempLeft = "";
int leftLength = leftOfSelection.length();
//If the left half has any size, chop the last character of the left half off,
//and reduce the caret position by one.
if(leftLength > 0)
{
tempLeft = leftOfSelection.substring(0, leftLength - 1);
caret--;
}
finalString = tempLeft + rightOfSelection;
}
//we assume that if you get here, the only option is for isDelete to be true.
else
{
String tempRight = "";
int rightLength = rightOfSelection.length();
//If the right half has any size, chop the first character of the right half off.
if(rightLength > 0)
{
tempRight = rightOfSelection.substring(1, rightLength);
}
finalString = leftOfSelection + tempRight;
}
}
}
//If we need to add something
else
{
//fbeninc cheched for \0 sent with shift.
if(keyString.equals(String.valueOf('\0')))finalString = currentString;
else {
caret = leftOfSelection.length() + 1;
finalString = leftOfSelection + keyString + rightOfSelection;
}
}
//Since there is no formatting, the finalString is the same as the unformattedString.
unformattedCurrent = finalString;
}
//We need to wory about a mask
else
{
boolean isBeep = false;
int i;
int maskIndex;
int unformattedLength = unformattedCurrent.length();
String newLeft;
String newRight = "";
String tempString = "";
String newPartialUnformatted = "";
String maskTemplate = getMaskTemplateString();
//Count the number of possible non-escape characters before the start of the selection
int numCharsBeforeSelStart = countNonEscapeChars(0, selStart);
if(isSelection)
{
//We are typing over the selection, not deleting it.
if(!(isBackspace || isDelete))
{
//Find the first non-escape character in the selection
maskIndex = selStart;
while(maskIndex < maskStripEscapesLen)
{
if(isEscape(maskIndex))
{
++maskIndex;
}
else
break;
}
//If the new character is not valid at this index, eat it, beep, and do nothing.
if(applyMaskToChar(keyString.charAt(0), maskIndex) == "")
{
Toolkit.getDefaultToolkit().beep();
return;
}
}
//Count the number of real characters in the selection
int numCharsInSelection = 0;
i = 0;
maskIndex = 0;
while(i < unformattedLength && maskIndex < maskStripEscapesLen)
{
if(!isEscape(maskIndex))
{
++i;
if(maskIndex >= selStart && maskIndex < selEnd)
{
++numCharsInSelection;
}
}
++maskIndex;
}
//If the selection contains characters we care about
if(numCharsInSelection > 0)
{
//We can assume that since the selection contains real characters, all non-escaped
//characters before the selection are real too.
//Remove the selected characters from the unformatted string
String tempL = numCharsBeforeSelStart > 0 ? unformattedCurrent.substring(0, numCharsBeforeSelStart) : "";
int tempIndex = numCharsBeforeSelStart + numCharsInSelection;
String tempR = tempIndex < unformattedLength ? unformattedCurrent.substring(tempIndex) : "";
unformattedCurrent = tempL + tempR;
//Recalculate unformattedLength
unformattedLength = unformattedCurrent.length();
}
//The selection doesn't contain any real characters, but we need handle selections of just escape characters
else
{
int numNonEscapeChars = countNonEscapeChars(selStart, selEnd);
//The selection contains only escape characters
if(numNonEscapeChars == 0)
{
Toolkit.getDefaultToolkit().beep();
return;
}
}
}
//There was no selection
else
{
if(isBackspace)
{
//Count the number of real characters before the selection
int numCharsBeforeSelection = 0;
i = 0;
maskIndex = 0;
while(i < unformattedLength && maskIndex < maskStripEscapesLen)
{
if(!isEscape(maskIndex))
{
++i;
if(maskIndex < selStart)
{
++numCharsBeforeSelection;
}
else
break;
}
++maskIndex;
}
//Move the caret past any consecutive escape characters
while(caret >= 0)
{
if(isEscape(caret - 1))
{
--caret;
}
else
break;
}
//Move the caret back one for the deleted character
--caret;
//If there is a gap between characters we care about and the selection, just move the caret
if(numCharsBeforeSelection < numCharsBeforeSelStart)
{
//Set the position of the caret
select(caret, caret);
return;
}
//There is no gap, and we need to delete a character
else
{
//Remove the character from the unformattedCurrent string
//A negative index is okay, since removeCharAtIndex will return the original in that case.
unformattedCurrent = symantec.itools.util.GeneralUtils.removeCharAtIndex(unformattedCurrent, numCharsBeforeSelection - 1);
//Recalculate unformattedLength
unformattedLength = unformattedCurrent.length();
}
}
else if(isDelete)
{
//Count the number of real characters after the selection
int numCharsAfterSelection = 0;
i = 0;
maskIndex = 0;
while(i < unformattedLength && maskIndex < maskStripEscapesLen)
{
if(!isEscape(maskIndex))
{
++i;
if(maskIndex >= selEnd)
{
++numCharsAfterSelection;
}
}
++maskIndex;
}
//If there are real characters in front of the cursor, delete one.
//We assume that there is no gap and start dierctly after the cursor.
if(numCharsAfterSelection > 0)// unformattedLength - numCharsBeforeSelStart)
{
int tempStart = numCharsBeforeSelStart < unformattedLength ? numCharsBeforeSelStart : unformattedLength - 1;
//Remove the character from the unformattedCurrent string
unformattedCurrent = symantec.itools.util.GeneralUtils.removeCharAtIndex(unformattedCurrent, tempStart);
//Recalculate unformattedLength
unformattedLength = unformattedCurrent.length();
}
//There are no characters we care about on the right of the cursor, so
//beep, and do nothing.
else
{
Toolkit.getDefaultToolkit().beep();
return;
}
}
}
numCharsBeforeSelStart = countNonEscapeChars(0, caret);
//If there is a gap between the current insertion point and the last character
//calculate the index of the current characters in the template, move the caret,
//and calculate a new left.
if(unformattedLength < numCharsBeforeSelStart)
{
i = 0;
maskIndex = 0;
while(i < unformattedLength && maskIndex < maskStripEscapesLen)
{
if(!isEscape(maskIndex))
{
++i;
}
++maskIndex;
}
//If there was a backspace, we let it's code handle caret manipulation
if(!isBackspace)
caret = maskIndex;
}
//If there is no gap, use the start of the selection to insert with.
else
{
maskIndex = caret; //The index in the formatted string
}
//Get the left characters
newLeft = maskIndex > 0 ? currentString.substring(0, maskIndex) : "";
//Apply the mask to the remaining non-escape characters in the right of selection and the new char
//fbeninc
String tempUnformatted;
if(keyString.equals(String.valueOf('\0')))
{
tempUnformatted =unformattedCurrent.substring(numCharsBeforeSelStart <= unformattedLength ? numCharsBeforeSelStart : unformattedLength);
caret--;
}
else
{
tempUnformatted = keyString + unformattedCurrent.substring(numCharsBeforeSelStart <= unformattedLength ? numCharsBeforeSelStart : unformattedLength);
}
//Here 'i' is the index in the unformattedCurrent string, and
i = 0;
while(i < tempUnformatted.length() && maskIndex < maskStripEscapesLen)
{
if(isEscape(maskIndex))
{
newRight += maskTemplate.charAt(maskIndex);
}
else
{
tempString = applyMaskToChar(tempUnformatted.charAt(i), maskIndex);
//If the character was filtered out by the mask the we need to beep
if(tempString == "")
{
isBeep = true;
}
//If the first character was accepted and we have a new character, then move the caret forward
else if(i == 0 && keyString != "")
{
//Move the caret past any consecutive escape characters
while(caret < maskStripEscapesLen)
{
if(isEscape(caret))
{
++caret;
}
else
break;
}
//Move the caret one for the character that was accepted.
++caret;
//Now that the caret has moved, move the caret past any consecutive escape characters
while(caret < maskStripEscapesLen)
{
if(isEscape(caret))
{
++caret;
}
else
break;
}
}
//Keep track of the new acceptable characters
newPartialUnformatted += tempString;
//Keep track of the characters to display
newRight += tempString;
//Go on to the next character
++i;
}
maskIndex++;
}
//Set the final string to the left, the newly constructed right, and any remainder of the mask template
finalString = newLeft + newRight + maskTemplate.substring(newLeft.length() + newRight.length());
//Set the unformattedCurrent to the unchanged left unformatted string and new right unformatted string.
unformattedCurrent = unformattedCurrent.substring(0, numCharsBeforeSelStart <= unformattedLength ? numCharsBeforeSelStart : unformattedLength) + newPartialUnformatted;
//Don't need to recalculate unformattedLength because it's not used after this
if(isBeep)
Toolkit.getDefaultToolkit().beep();
}
//Set the field's contents to our finalString
super.setText(finalString);
//Set the position of the caret
select(caret, caret);
}
/**
* Counts the possible number of non-escape characters before the given index.
* @param int start the index in the mask template to start from. Inclusive.
* @param int beforeIndex the index in the mask template to count back from. Exclusive.
* @return int the number of possible non-escape characters allowed before the given index.
*/
protected int countNonEscapeChars(int start, int beforeIndex)
{
int numChars = 0;
for(int i = start; i < beforeIndex; ++i)
{
if(!isEscape(i))
numChars++;
}
return numChars;
}
private boolean isEscape(int index)
{
return (index < 0 || index >= maskStripEscapesLen) ? false : (maskStripEscapes.charAt(index) == ESCAPE);
}
private String stripMaskEscapes()
{
if(mask == null)
{
return "";
}
else
{
int ml = mask.length();
int maskIndex = 0;
String nm = "";
while (maskIndex < ml)
{
char maskChar = mask.charAt(maskIndex++);
if (maskChar == ESCAPE)
++maskIndex;
nm += maskChar;
}
return nm;
}
}
/**
* The string passed to setText at design time. Returned from getText at design time.
*/
protected String designTimeText;
/**
* Character constant, the backspace character.
*/
protected final int BACKSPACE = 8;
/**
* Character constant, the enter character.
*/
protected final int ENTER = 10;
/**
* Character constant, the delete character.
*/
protected final int DEL = 127;
/**
* The zero-relative index of the character after the insertion point caret.
*/
protected int caret;
/**
* The valid string format mask used to define legal field input.
*/
protected String mask = null;
/**
* The valid characters currently in the textfield, with no formatting.
*/
protected String unformattedCurrent;
/**
* A string containing all the mask string characters except the ones immediately after ESCAPE characters.
*/
protected String maskStripEscapes;
/**
* The length of maskStripEscapes.
*/
protected int maskStripEscapesLen;
private Key keyListener = null;
}