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