package DisplayProject;
import java.text.AttributedCharacterIterator;
import java.text.ParseException;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.NumberFormat.Field;
import java.util.Map;
import javax.swing.JFormattedTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import Framework.DoubleData;
import Framework.NullAwareNumberFormat;
import Framework.NumericData;
/**
* For numeric types which are formatted, we need to provide a document filter to get the same behaviour as Forte.
* For example, if the field has a value of $1,234.56 and we have the cursor after the decimal place and before the
* 5 and the user hits backspace, we want to remove the 4, not the decimal point. This class handles this custom
* document manipulation.
* <p>
* It is assumed that this class will be used in conjunction with a FormattedNumericNavigationFilter
* @author Tim
*/
public class FormattedNumericDocumentFilter extends DocumentFilter {
/**
* A flag which prevents this class from going into an infinite loop.
*/
private boolean preventReentrant = false;
/**
* The decimal format underlying this formatted field
*/
protected NullAwareNumberFormat format;
/**
* The JFormattedTextField to which we are bound
*/
protected JFormattedTextField field;
/**
* On formatted data fields, the user should be able to enter say "-" followed by "6" if the value is
* zero to get the value -6. However, if we're zero we don't have a set value to store the sign, so we
* have to explicitly remember it.
*/
private enum PendingSign {NEGATIVE, POSITIVE, UNSET};
private PendingSign pendingSign = PendingSign.UNSET;
/**
* Create a new document filter with the passed format and the passed field. Note that this method
* does not attach the document filter onto the field.
* @param format
* @param field
*/
public FormattedNumericDocumentFilter(NullAwareNumberFormat format, JFormattedTextField field) {
this.format = format;
this.field = field;
}
/**
* @deprecated -- this constructor is provided to allow the clone helper to make a copy of this class
*/
public FormattedNumericDocumentFilter() {
}
/**
* Determine the offset from the start of the string where two strings co-incide. That is, it will return the largest
* index i such that pOriginalText.substring(i) = pNewText(j) where j = pNewText.length() - (pOriginalText.length() - i)
* <p>
* For example, consider $12,345,678.90 and $5,556.90. In this case, the return value would be where the decimal point is,
* ie 11
* <p>
* If the 2 strings are never co-incident, pOriginalText.length() is returned.
* @param pOriginalText
* @param pNewText
* @return
*/
private int getReplaceToOffset(String pOriginalText, String pNewText) {
int originalLength = pOriginalText.length();
int newLength = pNewText.length();
for (int i = 1; i <= originalLength; i++) {
if (newLength - i < 0) {
// The old string is longer, but apart from that they are right-equal.
return originalLength - newLength;
}
else if (pOriginalText.charAt(originalLength - i) != pNewText.charAt(newLength - i)) {
return originalLength - i + 1;
}
}
return 0;
}
/**
* Return the maximum number of decimal places that this format, for this value, can have. There
* is a difference to standard java -- a normal decimal format can have only a single number of
* decimal places, but in Forte, because there are multiple distinct masks, positive, negative,
* zero and null, we can have different numbers of decimal places based on the passed value
* @param value
* @param isNull
* @return
*/
protected int getMaximumDecimalPlaces(double value, boolean isNull) {
int maximumDecimalPlaces;
// For null aware formatters, the number of decimal places can vary based on the mask...
if (isNull) {
maximumDecimalPlaces = ((NullAwareNumberFormat)this.format).getMaximumFractionDigits((Double)null);
}
else {
maximumDecimalPlaces = ((NullAwareNumberFormat)this.format).getMaximumFractionDigits(value);
}
return maximumDecimalPlaces;
}
/**
* Invoked prior to insertion of text into the
* specified Document. Subclasses that want to conditionally allow
* insertion should override this and only call supers implementation as
* necessary, or call directly into the FilterBypass.
*
* @param fb FilterBypass that can be used to mutate Document
* @param offset the offset into the document to insert the content >= 0.
* All positions that track change at or after the given location
* will move.
* @param string the string to insert
* @param attr the attributes to associate with the inserted
* content. This may be null if there are no attributes.
* @exception BadLocationException the given insert position is not a
* valid position within the document
*/
@Override
public void insertString(javax.swing.text.DocumentFilter.FilterBypass fb, int offset, String string,
AttributeSet attr) throws BadLocationException {
if (preventReentrant) {
super.insertString(fb, offset, string, attr);
}
else {
PendingSign pendingSignToUse = PendingSign.UNSET;
boolean isSignChar = (string.length() == 1 && (string.charAt(0) == '+' || string.charAt(0) =='-'));
// Strip out any non-digits in the input string
int insertStringLength = string.length();
// TF:9/4/08:Changed to StringBuilder for efficiency.
StringBuilder realValueToInsert = new StringBuilder(insertStringLength);
for (int i = 0; i < insertStringLength; i++) {
if (Character.isDigit(string.charAt(i))) {
realValueToInsert.append(string.charAt(i));
}
}
if (realValueToInsert.length() == 0 && !isSignChar) {
return;
}
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
// get the current value as a number
int maximumDecimalPlaces = 0;
boolean isNegative = false;
Object o = null;
try {
o = this.field.getFormatter().stringToValue(text);
double value = 0.0;
if (o instanceof Number) {
value = ((Number)o).doubleValue();
}
else if (o instanceof NumericData) {
value = ((NumericData)o).doubleValue();
}
isNegative = (value < 0.0);
maximumDecimalPlaces = this.getMaximumDecimalPlaces(value, o == null);
}
catch (ParseException e) {
e.printStackTrace();
}
// TF:9/4/08: Changed this to a StringBuilder for performance reasons
StringBuilder stringVal = new StringBuilder(fb.getDocument().getLength()+string.length());
int decimalPlaceLocation = -1;
int count = 0;
int insertLocationInNewString = -1;
//int originalDPLoc = -1;
AttributedCharacterIterator iterator = format.formatToCharacterIterator(o);
if (iterator != null) {
for (char c = iterator.first(); c != AttributedCharacterIterator.DONE; c = iterator.next()) {
Map<Attribute, Object> map = iterator.getAttributes();
if (count == offset) {
insertLocationInNewString = stringVal.length();
}
if (map.containsKey(Field.GROUPING_SEPARATOR)) {
// Do nothing. Needed as the Grouping separator is also an integer!
}
else if (map.containsKey(Field.DECIMAL_SEPARATOR)) {
decimalPlaceLocation = stringVal.length();
//originalDPLoc = count;
}
else if (map.containsKey(Field.INTEGER) || map.containsKey(Field.FRACTION)) {
stringVal.append(c);
}
count++;
}
}
// Special case: if they use a format like "#,##0.##" we need to end in a ".". However,
// the java masks don't do this, so we explicitly force it. Unfortunately, the iterator
// cannot be altered, so we need to cater for it here...
boolean endsWithDecimalPoint = false;
// TF:29 sept. 2008:Fixed this to use an international character separator
if (text.endsWith(DoubleData.getDecimalSeparatorStr()) && decimalPlaceLocation < 0) {
decimalPlaceLocation = stringVal.length();
endsWithDecimalPoint = true;
//originalDPLoc = text.length();
}
// CraigM:23/07/2008 - If they have a blank as zero template, ignore the 0 value
if (this.format.isBlankForZeroTemplate() && stringVal.length() == 1 && stringVal.charAt(0) == '0') {
stringVal.delete(0, 1);
}
// TF:10/04/2008: We need to see if there are any trailing 0's to add back onto the character
// string, in case of masks like #,##0.#### and attempting to enter say 0.001
// if (originalDPLoc < 0 && text.lastIndexOf('.') > 0) {
// originalDPLoc = text.lastIndexOf('.');
// }
// System.out.println("originalDPloc = " + originalDPLoc);
// System.out.println("text.length = " + text.length());
// System.out.println("stringval.length = " + stringVal.length());
// System.out.println("decimalplaceLocation = " + decimalPlaceLocation);
// System.out.println("maximumDecimalPlaces = " + maximumDecimalPlaces);
// if (originalDPLoc > 0) {
// boolean skipLoop = false;
// if (decimalPlaceLocation < 0) {
// if (text.lastIndexOf('0') > originalDPLoc) {
// // There's no decimal place, but it looks like we need it.
// decimalPlaceLocation = stringVal.length();
// endsWithDecimalPoint = false;
// }
// else {
// skipLoop = true;
// }
// }
// if (!skipLoop) {
// for (int i = text.length() - 1; i > originalDPLoc && stringVal.length() - decimalPlaceLocation < maximumDecimalPlaces; i--) {
//System.out.println("text[" + i + "] = " + text.charAt(i));
// if (text.charAt(i) == '0') {
// stringVal.append('0');
// }
// else if (Character.isDigit(text.charAt(i))) {
// break;
// }
// }
// }
// }
// System.out.println("StringVal after loop: " + stringVal);
// If we haven't encountered the place to insert this string yet, we need to do so at the end of the string
boolean insertingAtEndOfString = false;
if (insertLocationInNewString == -1) {
insertLocationInNewString = stringVal.length();
insertingAtEndOfString = true;
}
String newValue = "";
stringVal.insert(insertLocationInNewString, realValueToInsert);
if (decimalPlaceLocation >= 0) {
int len = realValueToInsert.length();
if (insertLocationInNewString > decimalPlaceLocation && decimalPlaceLocation >= 0 && len > 0) {
// Inserting the text after the decimal point
// TF:7/4/08:Corrected this logic. It used to work in all cases except where multiple
// characters were being inserted after the decimal point.
int placesAfterDecimalPoint = stringVal.length() - decimalPlaceLocation;
int placesToMove = placesAfterDecimalPoint - maximumDecimalPlaces;
if (placesToMove < 0) {
placesToMove = 0;
}
decimalPlaceLocation += placesToMove;
}
else if (endsWithDecimalPoint && insertingAtEndOfString) {
// We're inserting at the decimal point location. This is a special case -- the
// decimal place stays still unless there's not enough characters after the decimal point
int minLocation = stringVal.length() - maximumDecimalPlaces;
if (decimalPlaceLocation < minLocation) {
decimalPlaceLocation = minLocation;
}
}
else {
// Got to move the decimal point by the length of the string to insert
decimalPlaceLocation += len;
}
// TF:29 sept. 2008:We must leave this as a decimal point, as this is going to be formatted
// as a decimal, not displayed as a decimal
stringVal.insert(decimalPlaceLocation, '.');
Double d = Double.valueOf(stringVal.toString());
if (isSignChar) {
if ((d < 0 && string.charAt(0) =='+') || (d > 0 && string.charAt(0) == '-')) {
d = -d;
}
else if (d == 0) {
// Set the pending sign marker
pendingSignToUse = string.charAt(0) == '+' ? PendingSign.POSITIVE : PendingSign.NEGATIVE;
}
}
else if (isNegative && d > 0) {
d = -d;
}
if (!isSignChar && this.pendingSign != PendingSign.UNSET) {
if ((d < 0 && this.pendingSign == PendingSign.POSITIVE) || (d > 0 && this.pendingSign == PendingSign.NEGATIVE)) {
d = -d;
}
}
try {
int newMaximumDecimalPlaces = this.getMaximumDecimalPlaces(d, false);
// If the number of decimal places has changes, we're changing between masks, eg going
// from a zero mask to a positive mask. This can only happen if we're replacing all the
// characters, so we want to shift what we're inserting so the digit(s) we've entered
// are the least significant in the decimal places.
if (newMaximumDecimalPlaces != maximumDecimalPlaces && !isSignChar) {
while (newMaximumDecimalPlaces > maximumDecimalPlaces) {
d /= 10;
newMaximumDecimalPlaces--;
}
while (newMaximumDecimalPlaces < maximumDecimalPlaces) {
d *= 10;
newMaximumDecimalPlaces++;
}
newValue = this.field.getFormatter().valueToString(d);
}
else {
// TF:8/4/08:Need to separate this out to allow trailing zeros
newValue = this.field.getFormatter().valueToString(d);
//System.out.println("newValue = " + newValue);
//System.out.println("StringValue = " + stringVal);
// int dpIndex = stringVal.toString().lastIndexOf('.');
// int length = stringVal.length();
// int currentDecimalPlaces = length - dpIndex + 1;
//System.out.println("dpIndex = " + dpIndex);
//System.out.println("length = " + length);
//System.out.println("currentDcimalPlaces = " + currentDecimalPlaces);
// for (int i = 0; stringVal.charAt(length - i - 1) == '0' && length - i > dpIndex && currentDecimalPlaces < maximumDecimalPlaces; i++) {
// newValue = newValue.concat("0");
// currentDecimalPlaces++;
//System.out.println("newValue = " + newValue + ", currentDecimalPlaces = " + currentDecimalPlaces);
// }
}
}
catch (ParseException e) {
// This should never happen, just ignore it.
e.printStackTrace();
}
}
else {
Long l = Long.valueOf(stringVal.toString());
if (isSignChar) {
if ((l < 0 && string.charAt(0) =='+') || (l > 0 && string.charAt(0) == '-')) {
l = -l;
}
else if (l == 0) {
// Set the pending sign marker
pendingSignToUse = string.charAt(0) == '+' ? PendingSign.POSITIVE : PendingSign.NEGATIVE;
}
}
else if (isNegative && l > 0) {
l = -l;
}
if (!isSignChar && this.pendingSign != PendingSign.UNSET) {
if ((l < 0 && this.pendingSign == PendingSign.POSITIVE) || (l > 0 && this.pendingSign == PendingSign.NEGATIVE)) {
l = -l;
}
}
try {
int newMaximumDecimalPlaces = this.getMaximumDecimalPlaces(l, false);
// If the number of decimal places has changes, we're changing between masks, eg going
// from a zero mask to a positive mask. This can only happen if we're replacing all the
// characters, so we want to shift what we're inserting so the digit(s) we've entered
// are the least significant in the decimal places.
if (newMaximumDecimalPlaces != maximumDecimalPlaces && !isSignChar) {
double d = (double)l;
while (newMaximumDecimalPlaces > maximumDecimalPlaces) {
d /= 10;
newMaximumDecimalPlaces--;
}
while (newMaximumDecimalPlaces < maximumDecimalPlaces) {
d *= 10;
newMaximumDecimalPlaces++;
}
newValue = this.field.getFormatter().valueToString(d);
}
else {
newValue = this.field.getFormatter().valueToString(l);
}
}
catch (ParseException e) {
// This should never happen, just ignore it.
e.printStackTrace();
}
}
// Now StringVal should contain the new number to format.
preventReentrant = true;
int replaceToOffset = getReplaceToOffset(text, newValue);
int distanceFromOldEnd = text.length() - replaceToOffset;
int replaceLength = newValue.length() - distanceFromOldEnd;
String newString = newValue.substring(0, replaceLength);
super.replace(fb, 0, replaceToOffset, newString, attr);
preventReentrant = false;
this.pendingSign = pendingSignToUse;
}
}
/**
* Invoked prior to removal of the specified region in the
* specified Document. Subclasses that want to conditionally allow
* removal should override this and only call supers implementation as
* necessary, or call directly into the <code>FilterBypass</code> as
* necessary.
*
* @param fb FilterBypass that can be used to mutate Document
* @param offset the offset from the beginning >= 0
* @param length the number of characters to remove >= 0
* @exception BadLocationException some portion of the removal range
* was not a valid part of the document. The location in the exception
* is the first bad position encountered.
*/
@Override
public void remove(javax.swing.text.DocumentFilter.FilterBypass fb, int offset, int length)
throws BadLocationException {
if (preventReentrant) {
super.remove(fb, offset, length);
}
else {
this.pendingSign = PendingSign.UNSET;
// System.out.println("remove(" + offset + ", " + length + ")");
if (length > 0) {
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
// System.out.println("Initial text = " + text);
// String charsToRemove;
// If the user is trying to backspace over a special character, like a comma, we don't
// allow it, but instead move to the previous number. This only applies if the dot and mark
// of the filter are the same (ie, they don't have a highlighted selection)
JFormattedTextField comp = this.field;
if (length == 1 && comp.getCaret().getDot() == comp.getCaret().getMark()) {
while (offset >= 0 && !Character.isDigit(text.charAt(offset))) {
offset--;
}
if (offset < 0) {
// Nothing to do
return;
}
// else {
// charsToRemove = text.substring(offset, offset + length);
// }
}
// else {
// charsToRemove = text.substring(offset, offset + length);
// }
// System.out.println("Chars to remove = " + charsToRemove);
try {
Object o = comp.getFormatter().stringToValue(text);
String value = text;
// TF:11/04/2008: Check for null coming back in case it's a widget mapped to
// a nullable field with a null value
if (o != null) {
value = o.toString();
// System.out.println(o.toString() + " - " + o.getClass().toString());
char[] chars = text.toCharArray();
int srcIndex = offset-1;
int destIndex = offset + length-1;
while (destIndex >= 0) {
if (Character.isDigit(chars[destIndex])) {
//need to replace this digit with another one
while (srcIndex >= 0 && !Character.isDigit(chars[srcIndex])) {
srcIndex--;
}
if (srcIndex >= 0) {
// Replace this index with the source digit
chars[destIndex] = chars[srcIndex];
// Now drop the source index back one
srcIndex--;
}
else {
// No character, must replace with 0
chars[destIndex] = '0';
}
}
destIndex--;
}
// System.out.println("Current dot at:" + this.field.getCaret().getDot());
// System.out.println("Current mark at:" + this.field.getCaret().getMark());
// System.out.println("New value = " + new String(chars));
o = comp.getFormatter().stringToValue(new String(chars));
}
value = comp.getFormatter().valueToString(o);
int lengthToReplace = getReplaceToOffset(text, value);
lengthToReplace = Math.max(length + offset, lengthToReplace);
// System.out.println("new value = " + value);
// System.out.println("replacement length(" + text + ", " + value + ") = " + lengthToReplace);
this.preventReentrant = true;
int substrLength = value.length() - (text.length() - lengthToReplace);
super.replace(fb, 0, lengthToReplace, value.substring(0, substrLength), null);
this.preventReentrant = false;
return;
}
catch (ParseException e) {
super.remove(fb, offset, length);
}
}
super.remove(fb, offset, length);
}
}
/**
* Invoked prior to replacing a region of text in the
* specified Document. Subclasses that want to conditionally allow
* replace should override this and only call supers implementation as
* necessary, or call directly into the FilterBypass.
*
* @param fb FilterBypass that can be used to mutate Document
* @param offset Location in Document
* @param length Length of text to delete
* @param text Text to insert, null indicates no text to insert
* @param attrs AttributeSet indicating attributes of inserted text,
* null is legal.
* @exception BadLocationException the given insert position is not a
* valid position within the document
*/
@Override
public void replace(javax.swing.text.DocumentFilter.FilterBypass fb, int offset, int length, String string,
AttributeSet attrs) throws BadLocationException {
if (preventReentrant) {
super.replace(fb, offset, length, string, attrs);
}
else if (length == 0) {
// This is just an insert, call insert. This shouldn't happen
this.insertString(fb, offset, string, attrs);
}
else if (string.length() == 0) {
// This is just a remove, call remove. This shouldn't happen
this.remove(fb, offset, length);
}
else {
// System.out.println("replaceString(" + offset + ", " + length +", '" + string + "', " + attrs + ")");
boolean isSignChar = (string.length() == 1 && (string.charAt(0) == '+' || string.charAt(0) =='-'));
if (isSignChar) {
// The sign character will be squashed in the insert anyway and just change the sign of the number
this.insertString(fb, offset, string, attrs);
}
else {
// Most of the time, replace is equivalent to remove() followed by insert. However, not all the
// time. Consider a mask of $#,##0.00 and a value of 123. This is formatted as $1.23. If all the
// text is selected and the character "1" used to replace it, then the delete formats this as "$0.00"
// then the insert puts the 1 after the dollar sign, so we end up with "$10.00", instead of "$0.01"
// Strip out any non-digits in the input string
int insertStringLength = string.length();
StringBuilder realValueToInsert = new StringBuilder(insertStringLength);
for (int i = 0; i < insertStringLength; i++) {
if (Character.isDigit(string.charAt(i))) {
realValueToInsert.append(string.charAt(i));
}
}
if (realValueToInsert.length() == 0) {
return;
}
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
// System.out.println("Initial text = " + text);
// get the current value as a number
int maximumDecimalPlaces = 0;
boolean isNegative = false;
Object o = null;
try {
o = this.field.getFormatter().stringToValue(text);
double value = 0.0;
if (o instanceof Number) {
value = ((Number)o).doubleValue();
}
else if (o instanceof NumericData) {
value = ((NumericData)o).doubleValue();
}
isNegative = (value < 0.0);
maximumDecimalPlaces = this.getMaximumDecimalPlaces(value, o == null);
}
catch (ParseException e) {
e.printStackTrace();
}
StringBuilder stringVal = new StringBuilder(fb.getDocument().getLength()+string.length());
int decimalPlaceLocation = -1;
int count = 0;
int startOffset = Math.min(offset, offset + length);
int endOffset = Math.max(offset, offset + length);
int startInsertLocationInNewString = -1;
int endInsertLocationInNewString = -1;
int digitCharsToRemove = 0;
AttributedCharacterIterator iterator = format.formatToCharacterIterator(o);
if (iterator != null) {
for (char c = iterator.first(); c != AttributedCharacterIterator.DONE; c = iterator.next()) {
Map<Attribute, Object> map = iterator.getAttributes();
if (count == startOffset) {
startInsertLocationInNewString = stringVal.length();
}
if (count == endOffset) {
endInsertLocationInNewString = stringVal.length();
}
if (map.containsKey(Field.GROUPING_SEPARATOR)) {
// Do nothing. Needed as the Grouping separator is also an integer!
}
else if (map.containsKey(Field.DECIMAL_SEPARATOR)) {
decimalPlaceLocation = stringVal.length();
}
else if (map.containsKey(Field.INTEGER) || map.containsKey(Field.FRACTION)) {
stringVal.append(c);
if (startInsertLocationInNewString >= 0 && endInsertLocationInNewString < 0) {
// We're going to be removing this digit, need to count it
digitCharsToRemove++;
}
}
count++;
}
}
// If we haven't encountered the place to insert this string yet, we need to do so at the end of the string
if (startInsertLocationInNewString == -1) {
startInsertLocationInNewString = stringVal.length();
}
// TF:29 sept. 2008:Fixed this to use an international character separator
if (text.endsWith(DoubleData.getDecimalSeparatorStr()) && decimalPlaceLocation < 0) {
decimalPlaceLocation = stringVal.length();
}
// If we haven't encountered the place to insert this string yet, we need to do so at the end of the string
if (endInsertLocationInNewString == -1) {
endInsertLocationInNewString = stringVal.length();
}
String newValue = "";
int originalLength = stringVal.length();
stringVal.replace(startInsertLocationInNewString, endInsertLocationInNewString, realValueToInsert.toString());
if (decimalPlaceLocation >= 0) {
// For a replace, we normally don't move the decimal place location relative to the end of the string
// except if the end insert location is at the end of the string.
if (endInsertLocationInNewString == originalLength && startInsertLocationInNewString > decimalPlaceLocation) {
// The decimal point location doesn't change unless we exceed the maximum
if (stringVal.length() - decimalPlaceLocation > maximumDecimalPlaces) {
decimalPlaceLocation = stringVal.length() - maximumDecimalPlaces;
}
}
else {
decimalPlaceLocation = stringVal.length() - (originalLength - decimalPlaceLocation);
while (decimalPlaceLocation < 0) {
stringVal.insert(0, '0');
decimalPlaceLocation++;
}
}
// TF:29 sept. 2008:We must leave this as a decimal point, as this is going to be formatted
// as a decimal, not displayed as a decimal
stringVal.insert(decimalPlaceLocation, '.');
Double d = Double.valueOf(stringVal.toString());
if (isNegative && d > 0) {
d = -d;
}
try {
int newMaximumDecimalPlaces = this.getMaximumDecimalPlaces(d, false);
// If the number of decimal places has changes, we're changing between masks, eg going
// from a zero mask to a positive mask. This can only happen if we're replacing all the
// characters, so we want to shift what we're inserting so the digit(s) we've entered
// are the least significant in the decimal places.
if (newMaximumDecimalPlaces != maximumDecimalPlaces) {
while (newMaximumDecimalPlaces > maximumDecimalPlaces) {
d /= 10;
newMaximumDecimalPlaces--;
}
while (newMaximumDecimalPlaces < maximumDecimalPlaces) {
d *= 10;
newMaximumDecimalPlaces++;
}
}
newValue = this.field.getFormatter().valueToString(d);
}
catch (ParseException e) {
// This should never happen just ignore it.
e.printStackTrace();
}
}
else {
Long l = Long.valueOf(stringVal.toString());
if (isNegative && l > 0) {
l = -l;
}
try {
int newMaximumDecimalPlaces = this.getMaximumDecimalPlaces(l, false);
// If the number of decimal places has changes, we're changing between masks, eg going
// from a zero mask to a positive mask. This can only happen if we're replacing all the
// characters, so we want to shift what we're inserting so the digit(s) we've entered
// are the least significant in the decimal places.
if (newMaximumDecimalPlaces != maximumDecimalPlaces) {
double d = (double)l;
while (newMaximumDecimalPlaces > maximumDecimalPlaces) {
d /= 10;
newMaximumDecimalPlaces--;
}
while (newMaximumDecimalPlaces < maximumDecimalPlaces) {
d *= 10;
newMaximumDecimalPlaces++;
}
newValue = this.field.getFormatter().valueToString(d);
}
else {
newValue = this.field.getFormatter().valueToString(l);
}
}
catch (ParseException e) {
// This should never happen, just ignore it.
e.printStackTrace();
}
}
// System.out.println("replacement length(" + text + ", " + newValue + ") = " + getReplaceToOffset(text, newValue));
// Now StringVal should contain the new number to format.
preventReentrant = true;
int replaceToOffset = getReplaceToOffset(text, newValue);
int distanceFromOldEnd = text.length() - replaceToOffset;
int replaceLength = newValue.length() - distanceFromOldEnd;
super.replace(fb, 0, replaceToOffset, newValue.substring(0, replaceLength), attrs);
preventReentrant = false;
this.pendingSign = PendingSign.UNSET;
}
}
}
}