Coverage Report - net.wotonomy.ui.swing.components.NumericTextField
 
Classes in this File Line Coverage Branch Coverage Complexity
NumericTextField
0% 
0% 
3.556
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Blacksmith, Inc
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.ui.swing.components;
 20  
 
 21  
 /**
 22  
 * NumericTextField is a "smart" text field that restricts the user's input.  The
 23  
 * input is restructed to numeric only wich can be of two types: integer and real
 24  
 * numbers.  A range can also be placed on the text field.  The default type is
 25  
 * integer, with the being (Integer.MIN_VALUE, Integer.MAX_VALUE).
 26  
 *
 27  
 * @author rob@straylight.princeton.com
 28  
 * @author $Author: cgruber $
 29  
 * @version $Revision: 893 $
 30  
 */
 31  
 public class NumericTextField extends SmartTextField
 32  
 {
 33  
 
 34  
 /*******************************
 35  
 * CONSTANTS
 36  
 *******************************/
 37  
 
 38  
 /**
 39  
 * Restrict the text input to integers (whole numbers) only.
 40  
 */
 41  
    public final static int INTEGER = 0;
 42  
 
 43  
 /**
 44  
 * Restrict the text input to floating-point numbers only.
 45  
 */
 46  
    public final static int FLOAT = 1;
 47  
 
 48  0
    private Number maximumValue = null;
 49  0
    private Number minimumValue = null;
 50  
 
 51  0
    private boolean sign = false;
 52  0
    private int newCaretPosition = 0;
 53  0
    private int valueType = INTEGER;
 54  
 
 55  
 
 56  
 /*******************************
 57  
 * PUBLIC METHODS
 58  
 *******************************/
 59  
 
 60  
 /**
 61  
 * Default constructor.
 62  
 */
 63  
    public NumericTextField()
 64  
    {
 65  0
       this("", 0);
 66  0
    }
 67  
 
 68  
 /**
 69  
 * Constructor.
 70  
 * @param text The initial string the text field is set to.
 71  
 */
 72  
    public NumericTextField(String text)
 73  
    {
 74  0
       this(text, 0);
 75  0
    }
 76  
 
 77  
 /**
 78  
 * Constructor.
 79  
 * @param columns Width of the text field (in characters).
 80  
 */
 81  
    public NumericTextField(int columns)
 82  
    {
 83  0
       this("", columns);
 84  0
    }
 85  
 
 86  
 /**
 87  
 * Constructor.
 88  
 * @param text The initial string the text field is set to.
 89  
 * @param columns Width of the text field (in characters).
 90  
 */
 91  
    public NumericTextField(String text, int columns)
 92  
    {
 93  0
       super(text, columns);
 94  0
    }
 95  
 
 96  
 /**
 97  
 * Sets the upper limit of the range of numbers to accept.
 98  
 * @param newMaximumValue The maximum number accepted by the text field.
 99  
 */
 100  
    public void setMaximumValue(double newMaximumValue)
 101  
    {
 102  0
       if (newMaximumValue >= 0)
 103  
       {
 104  0
          maximumValue = new Double( newMaximumValue );
 105  0
       }
 106  
       else
 107  
       {
 108  0
          maximumValue = null;
 109  
       }
 110  0
    }
 111  
 
 112  
 /**
 113  
 * Returns the upper limit of the range of numbers to accept.
 114  
 * @return The maximum number accepted by this text field.
 115  
 */
 116  
    public double getMaximumValue()
 117  
    {
 118  0
       if ( valueType == INTEGER )
 119  
       {
 120  0
         return (maximumValue == null) ? (double) Integer.MAX_VALUE : maximumValue.doubleValue();
 121  
       }
 122  
       else
 123  
       {
 124  0
         return (maximumValue == null) ? Double.MAX_VALUE : maximumValue.doubleValue();
 125  
       }
 126  
    }
 127  
 
 128  
 /**
 129  
 * Sets the lower limit of the range of numbers to accept.
 130  
 * @param newMinimumValue The minimum number accepted by the text field.
 131  
 */
 132  
    public void setMinimumValue(double newMinimumValue)
 133  
    {
 134  0
       if (newMinimumValue <= 0)
 135  
       {
 136  0
          minimumValue  = new Double( newMinimumValue );
 137  0
       }
 138  
       else
 139  
       {
 140  0
          minimumValue = null;
 141  
       }
 142  0
    }
 143  
 
 144  
 /**
 145  
 * Returns the lower limit of the range of numbers to accept.
 146  
 * @return The minimum number accepted by this text field.
 147  
 */
 148  
    public double getMinimumValue()
 149  
    {
 150  0
       if ( valueType == INTEGER )
 151  
       {
 152  0
         return (minimumValue == null) ? (double) Integer.MIN_VALUE : minimumValue.doubleValue();
 153  
       }
 154  
       else
 155  
       {
 156  0
         return (minimumValue == null) ? -1.0*Double.MAX_VALUE : minimumValue.doubleValue();
 157  
         // NOTE: Double.MIN_VALUE returns the smallest positive value - oooops.
 158  
       }
 159  
    }
 160  
 
 161  
 /**
 162  
 * Sets which type of number this text field can accept.
 163  
 * @see #INTEGER
 164  
 * @see #FLOAT
 165  
 * @param newValueType The type of number to accept.
 166  
 */
 167  
    public void setValueType(int newValueType)
 168  
    {
 169  0
       if ((newValueType != INTEGER) && (newValueType != FLOAT))
 170  
       {
 171  0
          valueType = INTEGER;
 172  0
       }
 173  
       else
 174  
       {
 175  0
          valueType = newValueType;
 176  
       }
 177  0
    }
 178  
 
 179  
 /**
 180  
 * Returns which type of number this text field accepts.  The default is
 181  
 * integer.
 182  
 * @see #INTEGER
 183  
 * @see #FLOAT
 184  
 * @return The type of number to accept.
 185  
 */
 186  
    public int getValueType()
 187  
    {
 188  0
       return valueType;
 189  
    }
 190  
 
 191  
 /**
 192  
 * Returns the integer numeric value of the string in the text field.  The type
 193  
 * can be either integer of float.
 194  
 * @return The current value in the text field.
 195  
 */
 196  
    public int getIntValue()
 197  
    {
 198  0
       int value = 0;
 199  
 
 200  
       try
 201  
       {
 202  0
          value = Integer.parseInt(getText());
 203  
       }
 204  0
       catch (NumberFormatException e)
 205  
       {
 206  
          try
 207  
          {
 208  0
             Double dValue = Double.valueOf(getText());
 209  0
             value = dValue.intValue();
 210  
          }
 211  0
          catch (NumberFormatException ignored) {}
 212  0
       }
 213  
 
 214  0
       return value;
 215  
    }
 216  
 
 217  
 /**
 218  
 * Sets the text field to integer value specified.
 219  
 * @param aValue An integer value to display in the text field.
 220  
 */
 221  
    public void setIntValue(int aValue)
 222  
    {
 223  0
       setText(Integer.toString(aValue));
 224  0
    }
 225  
 
 226  
 /**
 227  
 * Returns the real number numeric value of the string in the text field.  The type
 228  
 * can be either integer of float.
 229  
 * @return The current value in the text field.
 230  
 */
 231  
    public double getDoubleValue()
 232  
    {
 233  0
       Double value = new Double(0);
 234  
 
 235  
       try
 236  
       {
 237  0
          value = Double.valueOf(getText());
 238  
       }
 239  0
       catch (NumberFormatException ignored) {}
 240  
 
 241  0
       return value.doubleValue();
 242  
    }
 243  
 
 244  
 /**
 245  
 * Sets the text field to the double value specified.  If the text field type is
 246  
 * FLOAT then the the number is display as a real number.  If the text field
 247  
 * type is INTEGER then the number is converted to a whole number for displaying.
 248  
 * @param aValue A double value to display in the text field.
 249  
 */
 250  
    public void setDoubleValue(double aValue)
 251  
    {
 252  0
        Double temp = new Double(aValue);
 253  
 
 254  0
        if (valueType == FLOAT)
 255  
        {
 256  0
           setText(temp.toString());
 257  0
        }
 258  
        else
 259  
        {
 260  0
           setText(Integer.toString(temp.intValue()));
 261  
        }
 262  0
    }
 263  
 
 264  
 /*******************************
 265  
 * PROTECTED METHODS
 266  
 *******************************/
 267  
 
 268  
    protected boolean isValidCharacter(char aChar)
 269  
    {
 270  0
       if (((aChar >= ' ') && (aChar <= '/')) || ((aChar >= ':') && (aChar <= '~')))
 271  
       {
 272  0
          if (aChar == '.')
 273  
          {
 274  0
              if ( valueType == FLOAT )
 275  
              {
 276  0
                  return true;
 277  
              }
 278  
              else
 279  
              {
 280  0
                  return false;
 281  
              }
 282  
          }
 283  0
          else if (aChar == '-')
 284  
          {
 285  0
              if ( getMinimumValue() < 0 )
 286  
              {
 287  0
                  return true;
 288  
              }
 289  
              else
 290  
              {
 291  0
                  return false;
 292  
              }
 293  
          }
 294  0
          else if (aChar == '+')
 295  
          {
 296  0
              if ( getMaximumValue() >= 0 )
 297  
              {
 298  0
                  return true;
 299  
              }
 300  
              else
 301  
              {
 302  0
                  return false;
 303  
              }
 304  
          }
 305  0
          return false;
 306  
       }
 307  0
       return true;
 308  
    }
 309  
 
 310  
    protected boolean isValidString(String aString)
 311  
    {
 312  0
       int iValue = 0;
 313  0
       double dValue = 0.0;
 314  
 
 315  0
       String tempString = new String(scanForSignChar(aString));
 316  
 
 317  0
       if ( valueType == INTEGER )
 318  
       {
 319  
           try
 320  
           {
 321  0
              iValue = Integer.parseInt(tempString);
 322  
           }
 323  0
           catch (NumberFormatException e1)
 324  
           {
 325  0
              if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0))
 326  
              {
 327  0
                 iValue = 0;
 328  0
              }
 329  
              else
 330  
              {
 331  0
                 return false;
 332  
              }
 333  0
           }
 334  0
           if ((((double)iValue) < getMinimumValue()) || (((double)iValue) > getMaximumValue()))
 335  
           {
 336  0
              return false;
 337  
           }
 338  
       }
 339  
       else
 340  
       {
 341  
           // Double.valueOf requires a zero before the decimal point
 342  0
           if ( tempString.startsWith( "." ) )
 343  
           {
 344  0
               tempString = "0" + tempString;
 345  
           }
 346  
           try
 347  
           {
 348  0
              dValue = Double.valueOf(tempString).doubleValue();
 349  
           }
 350  0
           catch (NumberFormatException e2)
 351  
           {
 352  0
              if ((tempString.compareTo("-") == 0) && (getMinimumValue() < 0.0))
 353  
              {
 354  0
                 dValue = 0.0;
 355  0
              }
 356  
              else
 357  
              {
 358  0
                 return false;
 359  
              }
 360  0
           }
 361  
 
 362  0
           if ((dValue < getMinimumValue()) || (dValue > getMaximumValue()))
 363  
           {
 364  0
              return false;
 365  
           }
 366  
       }
 367  
 
 368  0
       return true;
 369  
    }
 370  
 
 371  
    protected void postProcessing()
 372  
    {
 373  0
       if (sign)
 374  
       {
 375  0
          setText(scanForSignChar(getText()));
 376  0
          setCaretPosition(newCaretPosition);
 377  
       }
 378  0
       sign = false;
 379  0
    }
 380  
 
 381  
 
 382  
 /*******************************
 383  
 * PRIVATE METHODS
 384  
 *******************************/
 385  
 
 386  
    private String scanForSignChar(String aString)
 387  
    {
 388  0
       String newString = "";
 389  0
       boolean positive = false;
 390  0
       boolean negative = false;
 391  0
       int oldCaretPosition = getCaretPosition();
 392  0
       int charactersAdded = 0;
 393  
 
 394  0
       newCaretPosition = 0;
 395  
 
 396  0
       if (aString.length() <= 0)
 397  
       {
 398  0
          return aString;
 399  
       }
 400  
 
 401  0
       for (int i = 0; i < aString.length(); ++i)
 402  
       {
 403  0
          switch (aString.charAt(i))
 404  
          {
 405  0
             case '+': positive = true;
 406  0
                       break;
 407  0
             case '-': negative = true;
 408  0
                       break;
 409  0
             default:  newString += aString.charAt(i);
 410  0
                       charactersAdded++;
 411  
                       break;
 412  
          }
 413  
 
 414  0
          if ((i + 1) == oldCaretPosition)
 415  
          {
 416  0
             newCaretPosition = charactersAdded;
 417  
          }
 418  
       }
 419  
 
 420  0
       if ((!(positive)) && (negative))
 421  
       {
 422  0
          newString = "-" + newString;
 423  0
          newCaretPosition++;
 424  
       }
 425  
 
 426  0
       if (positive || negative)
 427  
       {
 428  0
          sign = true;
 429  
       }
 430  
 
 431  0
       return newString;
 432  
    }
 433  
 }
 434