Save This Page
Home » openjdk-7 » net.sf.raptor » ui » components » [javadoc | source]
    1   /*********************************************************************************
    2    *                                                                               *
    3    * Raptor - Rapid prototyping of Swing GUIs based on JavaBeans like Java objects *
    4    * Copyright (C) 2003  XCOM AG                                                   *
    5    *                                                                               *
    6    * This library is free software; you can redistribute it and/or                 *
    7    * modify it under the terms of the GNU Lesser General Public                    *
    8    * License as published by the Free Software Foundation; either                  *
    9    * version 2.1 of the License, or (at your option) any later version.            *
   10    *                                                                               *
   11    * This library is distributed in the hope that it will be useful,               *
   12    * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
   13    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
   14    * Lesser General Public License for more details.                               *
   15    *                                                                               *
   16    * You should have received a copy of the GNU Lesser General Public              *
   17    * License along with this library; if not, write to the Free Software           *
   18    * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA     *
   19    *                                                                               *
   20    *********************************************************************************/
   21   package net.sf.raptor.ui.components;
   22   
   23   import java.text.DecimalFormat;
   24   import java.text.ParseException;
   25   import java.text.ParsePosition;
   26   
   27   import javax.swing.text.AbstractDocument;
   28   import javax.swing.text.AttributeSet;
   29   import javax.swing.text.BadLocationException;
   30   import javax.swing.text.PlainDocument;
   31   
   32   public class NumericPlainDocument extends PlainDocument {
   33       
   34       /**
   35        * constructor
   36        */
   37       public NumericPlainDocument() {
   38           setFormat(null);
   39       }
   40       
   41   	/**
   42        * constructor
   43   	 */
   44       public NumericPlainDocument(DecimalFormat format) {
   45           setFormat(format);
   46       }
   47   
   48   	/**
   49        * constructor
   50        * 
   51   	 * @param content
   52   	 * @param format
   53   	 */    
   54       public NumericPlainDocument(AbstractDocument.Content content, DecimalFormat format) {
   55   
   56           super(content);
   57           setFormat(format);
   58           
   59           try {
   60               format.parseObject(content.getString(0, content.length()), parsePos);
   61           } catch (Exception e) {
   62               throw new IllegalArgumentException("Initial content not a valid number");
   63           }
   64           
   65           if (parsePos.getIndex() != content.length() - 1) {
   66               throw new IllegalArgumentException(
   67               "Initial content not a valid number");
   68           }
   69       }
   70   
   71   	/**
   72   	 * setFormat
   73   	 * 
   74   	 * @param fmt
   75   	 */    
   76       public void setFormat(DecimalFormat fmt) {
   77           this.format = fmt != null ? fmt :
   78               (DecimalFormat)defaultFormat.clone();
   79               
   80               decimalSeparator =
   81               format.getDecimalFormatSymbols().getDecimalSeparator();
   82               groupingSeparator =
   83               format.getDecimalFormatSymbols().getGroupingSeparator();
   84               positivePrefix = format.getPositivePrefix();
   85               positivePrefixLen = positivePrefix.length();
   86               negativePrefix = format.getNegativePrefix();
   87               negativePrefixLen = negativePrefix.length();
   88               positiveSuffix = format.getPositiveSuffix();
   89               positiveSuffixLen = positiveSuffix.length();
   90               negativeSuffix = format.getNegativeSuffix();
   91               negativeSuffixLen = negativeSuffix.length();
   92       }
   93   
   94   	/**
   95   	 * getFormat
   96   	 * 
   97   	 * @return
   98   	 */ 
   99       public DecimalFormat getFormat() {
  100           return format;
  101       }
  102   
  103   	/**
  104   	 * getNumberValue
  105   	 * 
  106   	 * @return
  107   	 * @throws ParseException
  108   	 */ 
  109       public Number getNumberValue() throws ParseException {
  110           try {
  111               String content = getText(0, getLength());
  112               parsePos.setIndex(0);
  113               Number result = format.parse(content, parsePos);
  114               if (parsePos.getIndex() != getLength()) {
  115                   throw new ParseException(
  116                   "Not a valid number: " + content, 0);
  117               }
  118               
  119               return result;
  120           } catch (BadLocationException e) {
  121               throw new ParseException("Not a valid number", 0);
  122           }
  123       }
  124   
  125   	/**
  126   	 * getLongValue
  127   	 * 
  128   	 * @return
  129   	 * @throws ParseException
  130   	 */ 
  131       public Long getLongValue() throws ParseException {
  132           Number result = getNumberValue();
  133           if ((result instanceof Long) == false) {
  134               throw new ParseException("Not a valid long", 0);
  135           }
  136           
  137           return (Long)result;
  138       }
  139   
  140   	/**
  141   	 * getDoubleValue
  142   	 * 
  143   	 * @return
  144   	 * @throws ParseException
  145   	 */ 
  146       public Double getDoubleValue() throws ParseException {
  147           Number result = getNumberValue();
  148           if ((result instanceof Long) == false &&
  149           (result instanceof Double) == false) {
  150               throw new ParseException("Not a valid double", 0);
  151           }
  152           
  153           if (result instanceof Long) {
  154               result = new Double(result.doubleValue());
  155           }
  156           
  157           return (Double)result;
  158       }
  159   
  160   	/**
  161   	 * insertString
  162   	 */ 
  163       public void insertString(int offset, String str, AttributeSet a) throws BadLocationException {
  164           if (str == null || str.length() == 0) {
  165               return;
  166           }
  167           
  168           Content content = getContent();
  169           int length = content.length();
  170           int originalLength = length;
  171           
  172           parsePos.setIndex(0);
  173           
  174           // Create the result of inserting the new data,
  175           // but ignore the trailing newline
  176           String targetString = content.getString(0, offset) + str +
  177           content.getString(offset, length - offset - 1);
  178           
  179           // Parse the input string and check for errors
  180           do {
  181               boolean gotPositive = targetString.startsWith(positivePrefix);
  182               boolean gotNegative = targetString.startsWith(negativePrefix);
  183               
  184               length = targetString.length();
  185               
  186               // If we have a valid prefix, the parse fails if the
  187               // suffix is not present and the error is reported
  188               // at index 0. So, we need to add the appropriate
  189               // suffix if it is not present at this point.
  190               if (gotPositive == true || gotNegative == true) {
  191                   String suffix;
  192                   int suffixLength;
  193                   int prefixLength;
  194                   
  195                   if (gotPositive == true && gotNegative == true) {
  196                       // This happens if one is the leading part of
  197                       // the other - e.g. if one is "(" and the other "(("
  198                       if (positivePrefixLen > negativePrefixLen) {
  199                           gotNegative = false;
  200                       } else {
  201                           gotPositive = false;
  202                       }
  203                   }
  204                   
  205                   if (gotPositive == true) {
  206                       suffix = positiveSuffix;
  207                       suffixLength = positiveSuffixLen;
  208                       prefixLength = positivePrefixLen;
  209                   } else {
  210                       // Must have the negative prefix
  211                       suffix = negativeSuffix;
  212                       suffixLength = negativeSuffixLen;
  213                       prefixLength = negativePrefixLen;
  214                   }
  215                   
  216                   // If the string consists of the prefix alone,
  217                   // do nothing, or the result won't parse.
  218                   if (length == prefixLength) {
  219                       break;
  220                   }
  221                   
  222                   // We can't just add the suffix, because part of it
  223                   // may already be there. For example, suppose the
  224                   // negative prefix is "(" and the negative suffix is
  225                   // "$)". If the user has typed "(345$", then it is not
  226                   // correct to add "$)". Instead, only the missing part
  227                   // should be added, in this case ")".
  228                   if (targetString.endsWith(suffix) == false) {
  229                       int i;
  230                       for (i = suffixLength - 1; i > 0 ; i--) {
  231                           if (targetString.regionMatches(length - i,
  232                           suffix, 0, i)) {
  233                               targetString += suffix.substring(i);
  234                               break;
  235                           }
  236                       }
  237                       
  238                       if (i == 0) {
  239                           // None of the suffix was present
  240                           targetString += suffix;
  241                       }
  242                       
  243                       length = targetString.length();
  244                   }
  245               }
  246               
  247               format.parse(targetString, parsePos);
  248               
  249               int endIndex = parsePos.getIndex();
  250               if (endIndex == length) {
  251                   break;		// Number is acceptable
  252               }
  253               
  254               // Parse ended early
  255               // Since incomplete numbers don't always parse, try
  256               // to work out what went wrong.
  257               // First check for an incomplete positive prefix
  258               if (positivePrefixLen > 0 &&
  259               endIndex < positivePrefixLen &&
  260               length <= positivePrefixLen &&
  261               targetString.regionMatches(0, positivePrefix, 0, length)) {
  262                   break;		// Accept for now
  263               }
  264               
  265               // Next check for an incomplete negative prefix
  266               if (negativePrefixLen > 0 &&
  267               endIndex < negativePrefixLen &&
  268               length <= negativePrefixLen &&
  269               targetString.regionMatches(0, negativePrefix, 0, length)) {
  270                   break;		// Accept for now
  271               }
  272               
  273               // Allow a number that ends with the group
  274               // or decimal separator, if these are in use
  275               char lastChar = targetString.charAt(originalLength - 1);
  276               int decimalIndex = targetString.indexOf(decimalSeparator);
  277               if (format.isGroupingUsed() &&
  278               lastChar == groupingSeparator &&
  279               decimalIndex == -1) {
  280                   // Allow a "," but only in integer part
  281                   break;
  282               }
  283               
  284               if(format.isParseIntegerOnly() == false &&
  285               lastChar == decimalSeparator &&
  286               decimalIndex == originalLength - 1) {
  287                   // Allow a ".", but only one
  288                   break;
  289               }
  290               
  291               // No more corrections to make: must be an error
  292               if (errorListener != null) {
  293                   errorListener.insertFailed(this, offset, str, a);
  294               }
  295               return;
  296           } while (true == false);
  297           
  298           // Finally, add to the model
  299           super.insertString(offset, str, a);
  300       }
  301   
  302   	/**
  303   	 * addInsertErrorListener
  304   	 * 
  305   	 * @param l
  306   	 */ 
  307       public void addInsertErrorListener(InsertErrorListener l) {
  308           if (errorListener == null) {
  309               errorListener = l;
  310               return;
  311           }
  312           throw new IllegalArgumentException("InsertErrorListener already registered");
  313       }
  314   
  315   	/**
  316   	 * removeInsertErrorListener
  317   	 * 
  318   	 * @param l
  319   	 */ 
  320       public void removeInsertErrorListener(InsertErrorListener l) {
  321           if (errorListener == l) {
  322               errorListener = null;
  323           }
  324       }
  325       
  326       /**
  327        * InsertErrorListener
  328        * 
  329        * @author thomasg
  330        *
  331        * To change the template for this generated type comment go to
  332        * Window>Preferences>Java>Code Generation>Code and Comments
  333        */
  334       public interface InsertErrorListener {
  335           public abstract void insertFailed(NumericPlainDocument doc,
  336           int offset, String str, AttributeSet a);
  337       }
  338       
  339       protected InsertErrorListener errorListener;
  340       protected DecimalFormat format;
  341       protected char decimalSeparator;
  342       protected char groupingSeparator;
  343       protected String positivePrefix;
  344       protected String negativePrefix;
  345       protected int positivePrefixLen;
  346       protected int negativePrefixLen;
  347       protected String positiveSuffix;
  348       protected String negativeSuffix;
  349       protected int positiveSuffixLen;
  350       protected int negativeSuffixLen;
  351       protected ParsePosition parsePos = new ParsePosition(0);
  352       protected static DecimalFormat defaultFormat =
  353       new DecimalFormat();
  354   }

Save This Page
Home » openjdk-7 » net.sf.raptor » ui » components » [javadoc | source]