001/** 002* Please feel free to use any fragment of the code in this file that you need 003* in your own work. As far as I am concerned, it's in the public domain. No 004* permission is necessary or required. Credit is always appreciated if you 005* use a large chunk or base a significant product on one of my examples, 006* but that's not required either. 007* 008* This code is distributed in the hope that it will be useful, 009* but WITHOUT ANY WARRANTY; without even the implied warranty of 010* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 011* 012* --- Joseph A. Huwaldt 013**/ 014package jahuwaldt.swing; 015 016import javax.swing.text.PlainDocument; 017import javax.swing.text.AttributeSet; 018import javax.swing.text.BadLocationException; 019 020import java.awt.Toolkit; 021import java.text.Format; 022import java.text.ParsePosition; 023import java.text.DecimalFormat; 024import java.text.DecimalFormatSymbols; 025 026 027/** 028* A formatted document that uses a user supplied Format object to 029* control the format of the text in the document. For example, 030* this document will ignore anything that isn't a number if a 031* NumberFormat is supplied. 032* 033* <p> Modified by: Joseph A. Huwaldt </p> 034* 035* @author Joseph A. Huwaldt Date: February 24, 2000 036* @version September 16, 2012 037**/ 038@SuppressWarnings("serial") 039public class FormattedDocument extends PlainDocument { 040 041 private Format format; 042 private ParsePosition pos = new ParsePosition(0); 043 private String decimalSymbol = null; 044 private String minusSignSymbol = null; 045 046 /** 047 * Construct a formatted document that uses the supplied Format object. 048 **/ 049 public FormattedDocument(Format f) { 050 format = f; 051 if (format instanceof DecimalFormat) { 052 DecimalFormatSymbols symbols = ((DecimalFormat)format).getDecimalFormatSymbols(); 053 decimalSymbol = String.valueOf(symbols.getDecimalSeparator()); 054 minusSignSymbol = String.valueOf(symbols.getMinusSign()); 055 } 056 } 057 058 /** 059 * Method that returns the Format used by this document. 060 **/ 061 public Format getFormat() { 062 return format; 063 } 064 065 /** 066 * Inserts some content into the document using the documents Format to validate 067 * what has be inserted. Inserting content causes a write lock 068 * to be held while the actual changes are taking place, followed by notification 069 * to the observers on the thread that grabbed the write lock. 070 * 071 * @param offs the starting offset >= 0 072 * @param str the string to insert; does nothing with null/empty strings 073 * @param a the attributes for the inserted content 074 **/ 075 @Override 076 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { 077 078 if (str == null || str.length() == 0) 079 return; 080 081 String currentText = getText(0, getLength()); 082 String beforeOffset = currentText.substring(0, offs); 083 String afterOffset = currentText.substring(offs, currentText.length()); 084 String proposedResult = beforeOffset + str + afterOffset; 085 086 // Work around a couple of "bugs" in DecimalFormat.parseObject(). 087 // Allow leading decimal places when typing in a number. 088 if (format instanceof DecimalFormat && 089 (proposedResult.equals(decimalSymbol) || proposedResult.equals(minusSignSymbol + decimalSymbol))) 090 super.insertString(offs, str, a); 091 092 093 else { 094 pos.setIndex(0); 095 format.parseObject(proposedResult, pos); 096 if (pos.getIndex() == proposedResult.length()) 097 super.insertString(offs, str, a); 098 099 else { 100 System.err.println("FormattedDocument.insertString() error."); 101 Toolkit.getDefaultToolkit().beep(); 102 } 103 } 104 } 105 106 /** 107 * Removes some content from the document. Removing content causes a write lock 108 * to be held while the actual changes are taking place. Observers are notified 109 * of the change on the thread that called this method. 110 * 111 * @param offs the starting offset >= 0 112 * @param len the number of characters to remove >= 0 113 **/ 114 @Override 115 public void remove(int offs, int len) throws BadLocationException { 116 String currentText = getText(0, getLength()); 117 String beforeOffset = currentText.substring(0, offs); 118 String afterOffset = currentText.substring(len + offs, currentText.length()); 119 String proposedResult = beforeOffset + afterOffset; 120 121 if (proposedResult.length() != 0) { 122 pos.setIndex(0); 123 format.parseObject(proposedResult, pos); 124 if (pos.getIndex() != proposedResult.length()) { 125 System.out.println("FormattedDocument.remove() error."); 126 Toolkit.getDefaultToolkit().beep(); 127 return; 128 } 129 } 130 131 super.remove(offs, len); 132 } 133}