Altered so that document events are never fired while the document contains
an invalid value. This was made extra hairy by the fact that the FilterBypass installed on a Document implements replace() by simply calling remove() and then insert(). That's fine and dandy and saves lots of code, I'm sure, but the each of them fires an event, resulting in two events when a replace() happens. I Created a special Document that suppresses 'remove' events from firing. Not a problem, because I've also structured the filter such that removes() end up being implemented as a replace() (due to the filtering and processing that we do to ensure that valid, properly formatted integers are always displayed) so the 'insert' event will take care of all our needs. git-svn-id: https://samskivert.googlecode.com/svn/trunk@1585 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -10,10 +10,12 @@ import java.text.ParseException;
|
||||
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import javax.swing.text.AbstractDocument;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DocumentFilter;
|
||||
import javax.swing.text.PlainDocument;
|
||||
|
||||
import com.samskivert.Log;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
@@ -56,9 +58,9 @@ public class IntField extends JTextField
|
||||
*/
|
||||
public IntField (int initial, int minValue, int maxValue)
|
||||
{
|
||||
if (minValue < 0) {
|
||||
throw new IllegalArgumentException("minValue must be at least 0");
|
||||
}
|
||||
super(new IntDocument(), format(initial), 5);
|
||||
|
||||
validateMinMax(minValue, maxValue);
|
||||
if (initial > maxValue || initial < minValue) {
|
||||
throw new IllegalArgumentException("initial value not between " +
|
||||
"min and max");
|
||||
@@ -67,13 +69,12 @@ public class IntField extends JTextField
|
||||
_maxValue = maxValue;
|
||||
|
||||
setHorizontalAlignment(JTextField.RIGHT);
|
||||
setColumns(5);
|
||||
|
||||
// create a document filter which enforces the restrictions on
|
||||
// what text may be entered. This is similar to the filter
|
||||
// that is configured in SwingUtil.setDocumentHelpers, only the
|
||||
// remove operation is modified to do the sneaky highlighting we do.
|
||||
final AbstractDocument doc = (AbstractDocument) getDocument();
|
||||
final IntDocument doc = (IntDocument) getDocument();
|
||||
doc.setDocumentFilter(new DocumentFilter() {
|
||||
public void remove (FilterBypass fb, int offset, int length)
|
||||
throws BadLocationException
|
||||
@@ -83,8 +84,7 @@ public class IntField extends JTextField
|
||||
current.substring(offset + length);
|
||||
// if the bit to be removed is still a valid value, go ahead
|
||||
if (unformatSafe(potential) >= _minValue) {
|
||||
fb.remove(offset, length);
|
||||
transform(fb);
|
||||
transform(fb, current, potential);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,27 +121,35 @@ public class IntField extends JTextField
|
||||
String s, AttributeSet attr)
|
||||
throws BadLocationException
|
||||
{
|
||||
fb.insertString(offset, s, attr);
|
||||
transform(fb);
|
||||
String current = doc.getText(0, doc.getLength());
|
||||
String potential = current.substring(0, offset) + s +
|
||||
current.substring(offset);
|
||||
transform(fb, current, potential);
|
||||
}
|
||||
|
||||
public void replace (FilterBypass fb, int offset, int length,
|
||||
String text, AttributeSet attrs)
|
||||
throws BadLocationException
|
||||
{
|
||||
fb.replace(offset, length, text, attrs);
|
||||
transform(fb);
|
||||
String current = doc.getText(0, doc.getLength());
|
||||
String potential = current.substring(0, offset) + text +
|
||||
current.substring(offset + length);
|
||||
transform(fb, current, potential);
|
||||
}
|
||||
|
||||
protected void transform (FilterBypass fb)
|
||||
protected void transform (FilterBypass fb,
|
||||
String current, String potential)
|
||||
throws BadLocationException
|
||||
{
|
||||
try {
|
||||
String text = doc.getText(0, doc.getLength());
|
||||
String xform = transform(text);
|
||||
if (!text.equals(xform)) {
|
||||
fb.replace(0, text.length(), xform, null);
|
||||
}
|
||||
} catch (BadLocationException ble) {
|
||||
boolean wouldaBeenEqual = current.equals(potential);
|
||||
potential = transform(potential);
|
||||
// we only change it if it needs changing
|
||||
if (!current.equals(potential) ||
|
||||
// or if it would have been the same pre-transforming
|
||||
// and there is a selection (IE undo the selection)
|
||||
(wouldaBeenEqual &&
|
||||
(getSelectionEnd() != getSelectionStart()))) {
|
||||
fb.replace(0, doc.getLength(), potential, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,9 +213,20 @@ public class IntField extends JTextField
|
||||
return newText;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// and set the initial value
|
||||
setValue(initial);
|
||||
/**
|
||||
* Validate min/max.
|
||||
*/
|
||||
protected void validateMinMax (int minValue, int maxValue)
|
||||
{
|
||||
if (minValue < 0) {
|
||||
throw new IllegalArgumentException("minValue must be at least 0");
|
||||
}
|
||||
if (maxValue < minValue) {
|
||||
throw new IllegalArgumentException(
|
||||
"maxValue must be greater than minValue");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,9 +250,7 @@ public class IntField extends JTextField
|
||||
*/
|
||||
public void setMinValue (int minValue)
|
||||
{
|
||||
if (minValue < 0) {
|
||||
throw new IllegalArgumentException("minValue must be at least 0");
|
||||
}
|
||||
validateMinMax(minValue, _maxValue);
|
||||
_minValue = minValue;
|
||||
validateText();
|
||||
}
|
||||
@@ -243,6 +260,7 @@ public class IntField extends JTextField
|
||||
*/
|
||||
public void setMaxValue (int maxValue)
|
||||
{
|
||||
validateMinMax(_minValue, maxValue);
|
||||
_maxValue = maxValue;
|
||||
validateText();
|
||||
}
|
||||
@@ -286,6 +304,23 @@ public class IntField extends JTextField
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Our own special Document class.
|
||||
*/
|
||||
protected static class IntDocument extends PlainDocument
|
||||
{
|
||||
// documentation inherited
|
||||
protected void fireRemoveUpdate (DocumentEvent e)
|
||||
{
|
||||
// suppress: the DocumentFilter implements replace by doing
|
||||
// a remove and then an insert. We do not want listeners to ever
|
||||
// be notified when the document contains invalid text.
|
||||
// (Gosh, it'd be nice if we didn't have to hack this, but
|
||||
// the standard implementation has a bunch of methods with
|
||||
// package-protected access. Thanks Sun!)
|
||||
}
|
||||
}
|
||||
|
||||
/** min/max */
|
||||
protected int _minValue, _maxValue;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user