I made a minor additional change to paint the caret the same color as the text 
(white) when the text is invalid.
 
On Monday, March 23, 2009, at 01:52PM, "Todd Volkert" <[email protected]> 
wrote:
>Just noticed and changed one other thing:
>
>* Although we didn't have support for validations until this change,
>the original graphic design mock-ups did include such a state, and it
>had the background of the text input red, with the foreground white,
>so I changed TerraTextInputSkin to match the original mock-ups.  We
>generally try not to augment the color palette's base colors, as the
>original graphic designs (they came from within VMware) managed with
>just 8 base colors.
>
>-T
>
>On Mon, Mar 23, 2009 at 1:17 PM, Todd Volkert <[email protected]> wrote:
>> Hi Noel,
>>
>> I just submitted this patch - thanks!!  I did make a few minor
>> changes, mostly per our coding conventions, which I know you looked
>> for and couldn't find.  The substantive changes are listed below:
>>
>> * I changed TextInputListener#textValidatorChanged() to pass the
>> previous validator instead of the current one.  We generally try not
>> to pass information in events that can be obtained via API calls
>> (whereas the value that got overwritten would be lost if not passed in
>> the event).
>>
>> * I changed TextInputListener#textValidChanged() to not only pass one
>> argument.  Again, the isTextValid flag is superfluous since it can be
>> obtained via API, and the previous value is implied since it's a
>> boolean.
>>
>> * I changed TextInput#setValidator() to not throw if the text is
>> currently in an invalid state, to maintain parity with the
>> steady-state validation behavior.  Namely, if you have a validator set
>> on the TextInput, and you change the text in such a way as to make it
>> invalid, you don't get an exception; you simply get a textValidChanged
>> event.
>>
>> * I removed the repaint() call from TextInput#validateText().  The
>> event is sufficient.  It's the skin's job to trigger a repaint if it
>> wants to factor the validity of the text input into its paint() method
>> (which you were correctly doing in TerraTextInputSkin).
>>
>> -T
>>
>> On Mon, Mar 23, 2009 at 5:43 AM, Noel Grandin <[email protected]> wrote:
>>> Hi
>>>
>>> Apache ICLA sent to apache org.
>>>
>>> Applied changes from comments.
>>>
>>> Regards, Noel Grandin.
>>>
>>>
>>> Index: wtk-test/src/pivot/wtk/test/TextInputValidatorTest.java
>>> ===================================================================
>>> --- wtk-test/src/pivot/wtk/test/TextInputValidatorTest.java    (revision 0)
>>> +++ wtk-test/src/pivot/wtk/test/TextInputValidatorTest.java    (revision 0)
>>> @@ -0,0 +1,134 @@
>>> +/*
>>> + * Licensed under the Apache License, Version 2.0 (the "License");
>>> + * you may not use this file except in compliance with the License.
>>> + * You may obtain a copy of the License at
>>> + *
>>> + *     http://www.apache.org/licenses/LICENSE-2.0
>>> + *
>>> + * Unless required by applicable law or agreed to in writing, software
>>> + * distributed under the License is distributed on an "AS IS" BASIS,
>>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>>> + * See the License for the specific language governing permissions and
>>> + * limitations under the License.
>>> + */
>>> +package pivot.wtk.test;
>>> +
>>> +import pivot.collections.Dictionary;
>>> +import pivot.wtk.Application;
>>> +import pivot.wtk.Component;
>>> +import pivot.wtk.DesktopApplicationContext;
>>> +import pivot.wtk.Display;
>>> +import pivot.wtk.Label;
>>> +import pivot.wtk.TextInput;
>>> +import pivot.wtk.TextInputListener;
>>> +import pivot.wtk.Window;
>>> +import pivot.wtk.text.TextNode;
>>> +import pivot.wtk.text.validation.FloatRangeValidator;
>>> +import pivot.wtk.text.validation.IntRangeValidator;
>>> +import pivot.wtk.text.validation.RegexTextValidator;
>>> +import pivot.wtk.text.validation.Validator;
>>> +import pivot.wtkx.WTKXSerializer;
>>> +
>>> +public class TextInputValidatorTest implements Application {
>>> +    private Window window = null;
>>> +    private TextInput textinputFloatRange = null;
>>> +    private Label invalidLabel = null;
>>> +    private TextInput textinputIntRange = null;
>>> +    private TextInput textinputDateRegex = null;
>>> +    private TextInput textinputCustomBoolean = null;
>>> +
>>> +    public void startup(Display display, Dictionary<String, String>
>>> properties)
>>> +            throws Exception {
>>> +        WTKXSerializer wtkxSerializer = new WTKXSerializer();
>>> +        window = new Window((Component)
>>> wtkxSerializer.readObject(getClass()
>>> +                .getResource("textInputValidator_test.wtkx")));
>>> +        textinputFloatRange = (TextInput) wtkxSerializer
>>> +                .getObjectByName("textinputFloatRange");
>>> +        textinputIntRange = (TextInput) wtkxSerializer
>>> +                .getObjectByName("textinputIntRange");
>>> +        textinputDateRegex = (TextInput) wtkxSerializer
>>> +                .getObjectByName("textinputDateRegex");
>>> +        textinputCustomBoolean = (TextInput) wtkxSerializer
>>> +                .getObjectByName("textinputCustomBoolean");
>>> +
>>> +        // standard float range model
>>> +        textinputFloatRange.setText("0.5");
>>> +        textinputFloatRange.setValidator(new FloatRangeValidator(0.3f,
>>> +                2000f));
>>> +
>>> +        // test the listener by updating a label
>>> +        textinputFloatRange.getTextInputListeners().add(
>>> +                new TextInputListener() {
>>> +                    public void maximumLengthChanged(TextInput textInput,
>>> +                            int previousMaximumLength) {
>>> +                    }
>>> +
>>> +                    public void passwordChanged(TextInput textInput) {
>>> +                    }
>>> +
>>> +                    public void promptChanged(TextInput textInput,
>>> +                            String previousPrompt) {
>>> +                    }
>>> +
>>> +                    public void textKeyChanged(TextInput textInput,
>>> +                            String previousTextKey) {
>>> +                    }
>>> +
>>> +                    public void textNodeChanged(TextInput textInput,
>>> +                            TextNode previousTextNode) {
>>> +                    }
>>> +
>>> +                    public void textSizeChanged(TextInput textInput,
>>> +                            int previousTextSize) {
>>> +                    }
>>> +
>>> +                    public void textValidChanged(TextInput textInput,
>>> +                            boolean isTextValid) {
>>> +                        invalidLabel.setText(isTextValid ? "valid" :
>>> "invalid");
>>> +                    }
>>> +                    public void textValidatorChanged(TextInput textInput,
>>> +                            Validator validator) {
>>> +                    }
>>> +                });
>>> +
>>> +        invalidLabel = (Label)
>>> wtkxSerializer.getObjectByName("invalidLabel");
>>> +
>>> +        // standard int range model
>>> +        textinputIntRange.setText("0");
>>> +        textinputIntRange.setValidator(new IntRangeValidator(0, 100));
>>> +
>>> +        // validate using a date regex.
>>> +        textinputDateRegex.setText("2009-09-01");
>>> +        textinputDateRegex
>>> +                .setValidator(new RegexTextValidator(
>>> +                        "(19|20)\\d\\d[- /.](0[1-9]|1[012])[-
>>> /.](0[1-9]|[12][0-9]|3[01])"));
>>> +
>>> +        // creating a custom model that only accepts "true" or "false"
>>> +        textinputCustomBoolean.setText("true");
>>> +        textinputCustomBoolean.setValidator(new Validator() {
>>> +            public boolean isValid(String s) {
>>> +                return "true".equals(s) || "false".equals(s);
>>> +            }
>>> +        });
>>> +
>>> +        window.setTitle("Text Input Validator Test");
>>> +        window.setMaximized(true);
>>> +        window.open(display);
>>> +    }
>>> +
>>> +    public boolean shutdown(boolean optional) {
>>> +        window.close();
>>> +        return true;
>>> +    }
>>> +
>>> +    public void resume() {
>>> +    }
>>> +
>>> +    public void suspend() {
>>> +    }
>>> +
>>> +    public static void main(String[] args) throws Exception {
>>> +        DesktopApplicationContext
>>> +                .main(new String[] {
>>> TextInputValidatorTest.class.getName() });
>>> +    }
>>> +}
>>> Index: wtk-test/src/pivot/wtk/test/textInputValidator_test.wtkx
>>> ===================================================================
>>> --- wtk-test/src/pivot/wtk/test/textInputValidator_test.wtkx    (revision 0)
>>> +++ wtk-test/src/pivot/wtk/test/textInputValidator_test.wtkx    (revision 0)
>>> @@ -0,0 +1,42 @@
>>> +<?xml version="1.0" encoding="UTF-8"?>
>>> +<!--
>>> +Licensed under the Apache License, Version 2.0 (the "License");
>>> +you may not use this file except in compliance with the License.
>>> +You may obtain a copy of the License at
>>> +
>>> +    http://www.apache.org/licenses/LICENSE-2.0
>>> +
>>> +Unless required by applicable law or agreed to in writing, software
>>> +distributed under the License is distributed on an "AS IS" BASIS,
>>> +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>>> +See the License for the specific language governing permissions and
>>> +limitations under the License.
>>> +-->
>>> +
>>> +<TablePane styles="{padding:6, verticalSpacing:8}"
>>> +    xmlns:wtkx="http://pivot-toolkit.org/wtkx/2008"; xmlns="pivot.wtk">
>>> +    <columns>
>>> +        <TablePane.Column width="-1"/>
>>> +        <TablePane.Column width="-1"/>
>>> +        <TablePane.Column width="-1"/>
>>> +    </columns>
>>> +    <rows>
>>> +        <TablePane.Row height="-1">
>>> +            <Label text="float range 0.3-2000"/>
>>> +            <TextInput wtkx:id="textinputFloatRange"/>
>>> +            <Label wtkx:id="invalidLabel"/>
>>> +        </TablePane.Row>
>>> +        <TablePane.Row height="-1">
>>> +            <Label text="int range 0-100"/>
>>> +            <TextInput wtkx:id="textinputIntRange"/>
>>> +        </TablePane.Row>
>>> +        <TablePane.Row height="-1">
>>> +            <Label text="date regex"/>
>>> +            <TextInput wtkx:id="textinputDateRegex"/>
>>> +        </TablePane.Row>
>>> +        <TablePane.Row height="-1">
>>> +            <Label text="custom boolean"/>
>>> +            <TextInput wtkx:id="textinputCustomBoolean"/>
>>> +        </TablePane.Row>
>>> +    </rows>
>>> +</TablePane>
>>> Index: wtk/src/pivot/wtk/TextInput.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/TextInput.java    (revision 756338)
>>> +++ wtk/src/pivot/wtk/TextInput.java    (working copy)
>>> @@ -23,6 +23,7 @@
>>>  import pivot.wtk.text.Node;
>>>  import pivot.wtk.text.NodeListener;
>>>  import pivot.wtk.text.TextNode;
>>> +import pivot.wtk.text.validation.Validator;
>>>
>>>  /**
>>>  * A component that allows a user to enter a single line of unformatted
>>> text.
>>> @@ -71,6 +72,18 @@
>>>                 listener.textKeyChanged(textInput, previousTextKey);
>>>             }
>>>         }
>>> +
>>> +        public void textValidChanged(TextInput textInput, boolean
>>> isTextValid) {
>>> +          for (TextInputListener listener : this) {
>>> +            listener.textValidChanged(textInput, isTextValid);
>>> +          }
>>> +        }
>>> +
>>> +        public void textValidatorChanged(TextInput textInput, Validator
>>> validator) {
>>> +            for (TextInputListener listener : this) {
>>> +              listener.textValidatorChanged(textInput, validator);
>>> +            }
>>> +         }
>>>     }
>>>
>>>     /**
>>> @@ -132,7 +145,9 @@
>>>     private boolean password = false;
>>>     private String prompt = null;
>>>     private String textKey = null;
>>> -
>>> +    private Validator validator = null;
>>> +    private boolean textValid = true;
>>> +
>>>     private NodeListener textNodeListener = new NodeListener() {
>>>         public void parentChanged(Node node, Element previousParent) {
>>>         }
>>> @@ -151,6 +166,7 @@
>>>
>>>
>>> textInputCharacterListeners.charactersInserted(TextInput.this, offset,
>>> characterCount);
>>>             textInputTextListeners.textChanged(TextInput.this);
>>> +            validateText();
>>>         }
>>>
>>>         public void rangeRemoved(Node node, int offset, int
>>> characterCount) {
>>> @@ -164,6 +180,7 @@
>>>
>>>
>>> textInputCharacterListeners.charactersRemoved(TextInput.this, offset,
>>> characterCount);
>>>             textInputTextListeners.textChanged(TextInput.this);
>>> +            validateText();
>>>         }
>>>     };
>>>
>>> @@ -191,7 +208,7 @@
>>>         if (textNode.getCharacterCount() > maximumLength) {
>>>             throw new IllegalArgumentException("Text length is greater
>>> than maximum length.");
>>>         }
>>> -
>>> +
>>>         TextNode previousTextNode = this.textNode;
>>>
>>>         if (previousTextNode != textNode) {
>>> @@ -211,6 +228,7 @@
>>>
>>>             textInputListeners.textNodeChanged(this, previousTextNode);
>>>             textInputTextListeners.textChanged(this);
>>> +            validateText();
>>>         }
>>>     }
>>>
>>> @@ -603,6 +621,42 @@
>>>         }
>>>     }
>>>
>>> +    public boolean isTextValid() {
>>> +        return this.textValid;
>>> +    }
>>> +
>>> +    /**
>>> +     * set the validator for the text field.
>>> +     *
>>> +     * @exception IllegalStateException if the current text is invalid
>>> according to the new TextValidator
>>> +     */
>>> +    public void setValidator(Validator validator) {
>>> +        if (validator != null && !validator.isValid(getText())) {
>>> +            throw new IllegalStateException(
>>> +                    "cannot set a TextValidator (" + validator + ")
>>> that results in the current text (" + getText() + ") being invalid");
>>> +        }
>>> +        this.validator = validator;
>>> +        textInputListeners.textValidatorChanged(this, this.validator);
>>> +        if (!textValid) {
>>> +            textValid = true;
>>> +            textInputListeners.textValidChanged(this, textValid);
>>> +        }
>>> +    }
>>> +
>>> +    public Validator getValidator() {
>>> +        return this.validator;
>>> +    }
>>> +
>>> +    private void validateText() {
>>> +        String text = getText();
>>> +        boolean b = validator == null ? true : validator.isValid(text);
>>> +        if (b != this.textValid) {
>>> +            this.textValid = b;
>>> +            textInputListeners.textValidChanged(this, textValid);
>>> +            repaint();
>>> +        }
>>> +    }
>>> +
>>>     /**
>>>      * Returns the text input listener list.
>>>      */
>>> Index: wtk/src/pivot/wtk/TextInputListener.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/TextInputListener.java    (revision 756338)
>>> +++ wtk/src/pivot/wtk/TextInputListener.java    (working copy)
>>> @@ -16,6 +16,7 @@
>>>  package pivot.wtk;
>>>
>>>  import pivot.wtk.text.TextNode;
>>> +import pivot.wtk.text.validation.Validator;
>>>
>>>  /**
>>>  * Text input listener interface.
>>> @@ -68,4 +69,17 @@
>>>      * @param previousTextKey
>>>      */
>>>     public void textKeyChanged(TextInput textInput, String
>>> previousTextKey);
>>> +
>>> +    /**
>>> +     * Called when the text changes validity.
>>> +     *
>>> +     * @param textInput
>>> +     * @param isTextValid is the text currently valid
>>> +     */
>>> +    public void textValidChanged(TextInput textInput, boolean isTextValid);
>>> +
>>> +    /**
>>> +     * Called when the validator changes..
>>> +     */
>>> +    public void textValidatorChanged(TextInput textInput, Validator
>>> validator);
>>>  }
>>> Index: wtk/src/pivot/wtk/skin/terra/TerraTextInputSkin.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/skin/terra/TerraTextInputSkin.java    (revision
>>> 756338)
>>> +++ wtk/src/pivot/wtk/skin/terra/TerraTextInputSkin.java    (working copy)
>>> @@ -39,12 +39,13 @@
>>>  import pivot.wtk.Mouse;
>>>  import pivot.wtk.Platform;
>>>  import pivot.wtk.TextInput;
>>> -import pivot.wtk.TextInputListener;
>>>  import pivot.wtk.TextInputCharacterListener;
>>> +import pivot.wtk.TextInputListener;
>>>  import pivot.wtk.TextInputSelectionListener;
>>>  import pivot.wtk.Theme;
>>>  import pivot.wtk.skin.ComponentSkin;
>>>  import pivot.wtk.text.TextNode;
>>> +import pivot.wtk.text.validation.Validator;
>>>
>>>  /**
>>>  * Text input skin.
>>> @@ -233,6 +234,7 @@
>>>     private Color promptColor;
>>>     private Color backgroundColor;
>>>     private Color disabledBackgroundColor;
>>> +    private Color invalidTextBackgroundColor;
>>>     private Color borderColor;
>>>     private Color disabledBorderColor;
>>>     private Insets padding;
>>> @@ -256,6 +258,7 @@
>>>         disabledColor = theme.getColor(7);
>>>         backgroundColor = theme.getColor(11);
>>>         disabledBackgroundColor = theme.getColor(10);
>>> +        invalidTextBackgroundColor = theme.getColor(25);
>>>         borderColor = theme.getColor(7);
>>>         disabledBorderColor = theme.getColor(7);
>>>         padding = new Insets(2);
>>> @@ -346,6 +349,9 @@
>>>             borderColor = this.disabledBorderColor;
>>>             bevelColor = disabledBevelColor;
>>>         }
>>> +        if (!textInput.isTextValid()) {
>>> +            backgroundColor = invalidTextBackgroundColor;
>>> +        }
>>>
>>>         graphics.setStroke(new BasicStroke());
>>>
>>> @@ -609,6 +615,32 @@
>>>         setBackgroundColor(theme.getColor(color));
>>>     }
>>>
>>> +    public Color getInvalidTextBackgroundColor() {
>>> +        return invalidTextBackgroundColor;
>>> +    }
>>> +
>>> +    public void setInvalidTextBackgroundColor(Color color) {
>>> +        if (invalidTextBackgroundColor == null) {
>>> +            throw new
>>> IllegalArgumentException("invalidTextBackgroundColor is null.");
>>> +        }
>>> +
>>> +        this.invalidTextBackgroundColor = color;
>>> +        repaintComponent();
>>> +    }
>>> +
>>> +    public final void setInvalidTextBackgroundColor(String color) {
>>> +        if (color == null) {
>>> +            throw new
>>> IllegalArgumentException("invalidTextBackgroundColor is null.");
>>> +        }
>>> +
>>> +        setInvalidTextBackgroundColor(decodeColor(color));
>>> +    }
>>> +
>>> +    public final void setInvalidTextBackgroundColor(int color) {
>>> +        TerraTheme theme = (TerraTheme)Theme.getTheme();
>>> +        setInvalidTextBackgroundColor(theme.getColor(color));
>>> +    }
>>> +
>>>     public Color getDisabledBackgroundColor() {
>>>         return disabledBackgroundColor;
>>>     }
>>> @@ -635,7 +667,7 @@
>>>         TerraTheme theme = (TerraTheme)Theme.getTheme();
>>>         setDisabledBackgroundColor(theme.getColor(color));
>>>     }
>>> -
>>> +
>>>     public Color getBorderColor() {
>>>         return borderColor;
>>>     }
>>> @@ -1064,20 +1096,19 @@
>>>     public void focusedChanged(Component component, boolean temporary) {
>>>         super.focusedChanged(component, temporary);
>>>
>>> -        TextInput textInput = (TextInput)getComponent();
>>> +        TextInput textInput = (TextInput) getComponent();
>>>         TextNode textNode = textInput.getTextNode();
>>>
>>>         if (component.isFocused()) {
>>>             showCaret(textInput.getSelectionLength() == 0);
>>>
>>> -            if (!temporary
>>> -                && Mouse.getCapturer() != component) {
>>> +            if (!temporary && Mouse.getCapturer() != component) {
>>>                 textInput.setSelection(0, textNode.getCharacterCount());
>>>             }
>>>         } else {
>>>             if (!temporary) {
>>>                 textInput.setSelection(textInput.getSelectionStart()
>>> -                    + textInput.getSelectionLength(), 0);
>>> +                        + textInput.getSelectionLength(), 0);
>>>             }
>>>
>>>             showCaret(false);
>>> @@ -1110,7 +1141,15 @@
>>>     public void textKeyChanged(TextInput textInput, String
>>> previousTextKey) {
>>>         // No-op
>>>     }
>>> -
>>> +
>>> +    public void textValidChanged(TextInput textInput, boolean isValid) {
>>> +        repaintComponent();
>>> +    }
>>> +
>>> +    public void textValidatorChanged(TextInput textInput, Validator
>>> validator) {
>>> +        // No-op
>>> +    }
>>> +
>>>     // Text input character events
>>>     public void charactersInserted(TextInput textInput, int index, int
>>> count) {
>>>         updateSelection();
>>> @@ -1207,4 +1246,5 @@
>>>
>>>         repaintComponent();
>>>     }
>>> +
>>>  }
>>> Index: wtk/src/pivot/wtk/skin/terra/TerraTheme_default.json
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/skin/terra/TerraTheme_default.json    (revision
>>> 756338)
>>> +++ wtk/src/pivot/wtk/skin/terra/TerraTheme_default.json    (working copy)
>>> @@ -9,6 +9,7 @@
>>>         "#2b5580",
>>>         "#3c77b2",
>>>         "#14538b",
>>> -        "#b0000f"
>>> +        "#b0000f",
>>> +        "#ffff00"
>>>     ]
>>>  }
>>> Index: wtk/src/pivot/wtk/text/validation/DecimalValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/DecimalValidator.java    (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/DecimalValidator.java    (revision 0)
>>> @@ -0,0 +1,36 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +import java.text.DecimalFormat;
>>> +import java.text.NumberFormat;
>>> +import java.text.ParseException;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public abstract class DecimalValidator extends
>>> FormattedValidator<NumberFormat>
>>> +{
>>> +    protected DecimalValidator(DecimalFormat format)
>>> +    {
>>> +        super(format);
>>> +    }
>>> +
>>> +    protected DecimalValidator()
>>> +    {
>>> +        super(NumberFormat.getInstance());
>>> +    }
>>> +
>>> +    /** helper for textToObject */
>>> +    protected final Number parse(String text)
>>> +    {
>>> +        try
>>> +        {
>>> +            return format.parse(text);
>>> +        }
>>> +        catch (ParseException ex)
>>> +        {
>>> +            // this should never happen
>>> +            throw new RuntimeException(ex);
>>> +        }
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/DoubleRangeValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/DoubleRangeValidator.java
>>> (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/DoubleRangeValidator.java
>>> (revision 0)
>>> @@ -0,0 +1,25 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class DoubleRangeValidator extends DoubleValidator
>>> +{
>>> +    private final double minValue, maxValue;
>>> +
>>> +    public DoubleRangeValidator(double minValue, double maxValue)
>>> +    {
>>> +        this.minValue = minValue;
>>> +        this.maxValue = maxValue;
>>> +    }
>>> +
>>> +   �...@override
>>> +    public boolean isValid(String text)
>>> +    {
>>> +        if (!super.isValid(text))
>>> +            return false;
>>> +        final double f = textToObject(text);
>>> +        return f >= minValue && f <= maxValue;
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/DoubleValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/DoubleValidator.java    (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/DoubleValidator.java    (revision 0)
>>> @@ -0,0 +1,17 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class DoubleValidator extends DecimalValidator
>>> +{
>>> +    public DoubleValidator()
>>> +    {
>>> +    }
>>> +
>>> +    protected final Double textToObject(String text)
>>> +    {
>>> +        return parse(text).doubleValue();
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/FloatRangeValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/FloatRangeValidator.java
>>> (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/FloatRangeValidator.java
>>> (revision 0)
>>> @@ -0,0 +1,25 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class FloatRangeValidator extends FloatValidator
>>> +{
>>> +    private final float minValue, maxValue;
>>> +
>>> +    public FloatRangeValidator(float minValue, float maxValue)
>>> +    {
>>> +        this.minValue = minValue;
>>> +        this.maxValue = maxValue;
>>> +    }
>>> +
>>> +   �...@override
>>> +    public boolean isValid(String text)
>>> +    {
>>> +        if (!super.isValid(text))
>>> +            return false;
>>> +        final float f = textToObject(text);
>>> +        return f >= minValue && f <= maxValue;
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/FloatValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/FloatValidator.java    (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/FloatValidator.java    (revision 0)
>>> @@ -0,0 +1,17 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class FloatValidator extends DecimalValidator
>>> +{
>>> +    public FloatValidator()
>>> +    {
>>> +    }
>>> +
>>> +    protected final Float textToObject(String text)
>>> +    {
>>> +        return parse(text).floatValue();
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/FormattedValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/FormattedValidator.java
>>> (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/FormattedValidator.java
>>> (revision 0)
>>> @@ -0,0 +1,26 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +import java.text.ParsePosition;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public abstract class FormattedValidator<TFormat extends
>>> java.text.Format> implements Validator
>>> +{
>>> +    protected final TFormat format;
>>> +
>>> +    protected FormattedValidator(TFormat format)
>>> +    {
>>> +        this.format = format;
>>> +    }
>>> +
>>> +    public boolean isValid(String text)
>>> +    {
>>> +        final ParsePosition pos = new ParsePosition(0);
>>> +        Object obj = format.parseObject(text, pos);
>>> +        // the text is only valid is we successfully parsed ALL of it.
>>> Don't want trailing bits of
>>> +        // not-valid text.
>>> +        return obj != null && pos.getErrorIndex() == -1 &&
>>> pos.getIndex() == text.length();
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/IntRangeValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/IntRangeValidator.java    (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/IntRangeValidator.java    (revision 0)
>>> @@ -0,0 +1,25 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class IntRangeValidator extends IntValidator
>>> +{
>>> +    private final int minValue, maxValue;
>>> +
>>> +    public IntRangeValidator(int minValue, int maxValue)
>>> +    {
>>> +        this.minValue = minValue;
>>> +        this.maxValue = maxValue;
>>> +    }
>>> +
>>> +   �...@override
>>> +    public boolean isValid(String text)
>>> +    {
>>> +        if (!super.isValid(text))
>>> +            return false;
>>> +        final int i = textToObject(text);
>>> +        return i >= minValue && i <= maxValue;
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/IntValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/IntValidator.java    (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/IntValidator.java    (revision 0)
>>> @@ -0,0 +1,18 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class IntValidator extends DecimalValidator
>>> +{
>>> +    public IntValidator()
>>> +    {
>>> +        format.setParseIntegerOnly(true);
>>> +    }
>>> +
>>> +    protected final Integer textToObject(String text)
>>> +    {
>>> +        return parse(text).intValue();
>>> +    }
>>> +}
>>> \ No newline at end of file
>>> Index: wtk/src/pivot/wtk/text/validation/RegexTextValidator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/RegexTextValidator.java
>>> (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/RegexTextValidator.java
>>> (revision 0)
>>> @@ -0,0 +1,25 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +import java.util.regex.Pattern;
>>> +
>>> +/**
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public class RegexTextValidator implements Validator {
>>> +
>>> +    private final Pattern p;
>>> +
>>> +    public RegexTextValidator(Pattern p) {
>>> +        this.p = p;
>>> +    }
>>> +
>>> +    public RegexTextValidator(String regexPattern) {
>>> +        this.p = Pattern.compile(regexPattern);
>>> +    }
>>> +
>>> +    public boolean isValid(String text) {
>>> +        return p.matcher(text).matches();
>>> +    }
>>> +
>>> +}
>>> Index: wtk/src/pivot/wtk/text/validation/Validator.java
>>> ===================================================================
>>> --- wtk/src/pivot/wtk/text/validation/Validator.java    (revision 0)
>>> +++ wtk/src/pivot/wtk/text/validation/Validator.java    (revision 0)
>>> @@ -0,0 +1,11 @@
>>> +package pivot.wtk.text.validation;
>>> +
>>> +/**
>>> + * Validation interface for TextInput widget.
>>> + *
>>> + * @author Noel Grandin
>>> + */
>>> +public interface Validator {
>>> +    /** Is the text value valid? */
>>> +    boolean isValid(String text);
>>> +}
>>> \ No newline at end of file
>>>
>>>
>>
>
>

Reply via email to