001 package util.swing; 002 003 import util.swing.InputFilter; 004 import java.awt.event.*; 005 import javax.swing.JTextField; 006 import javax.swing.text.*; 007 008 009 /** 010 * An input field that lets you easily set up input filters. 011 * 012 * <p>This class derives from JTextField and adds support for the {@link InputFilter} 013 * interface. This way you can validate input much more easily.</p> 014 * 015 * <p>The filters can react when the input content is changed and when the user exits 016 * the control. So, e.g. you can check while editing that it is an integer and when 017 * leaving check for correct input bounds. Doing so already when typing is quite 018 * problematic since not all number ranges can then be covered. </p> 019 * 020 * <p><b>Example</b> for using JFilterInput: This will allow only binary numbers for 021 * input. 022 * <br/><br/> 023 * <tt> JFilterInput jfiBinary = new JFilterInput(new InputFilter() {<br/> 024 * public boolean allowEditing(String value) {<br/> 025 * return !value.matches(".*[^01]+.*");<br/> 026 * }<br/> 027 * public String validExit(String value) {<br/> 028 * return value;<br/> }<br/> 029 * });</tt></p> 030 * 031 * @author Thomas Ryssel 032 * @version 3.2 033 * @since 3.2 2006-03-18 034 */ 035 public class JFilterInput extends JTextField { 036 037 /** 038 * ID for serialization. 039 */ 040 private static final long serialVersionUID = -6448548193991908200L; 041 042 /** 043 * The filter used for this input. If set to <code>null</code>, no filter 044 * will be applied. 045 */ 046 private InputFilter m_ifFilter = null; 047 048 /** 049 * Internal flag indicating that changes will be allowed without any 050 * conditions. 051 */ 052 private boolean m_bForceAllow = false; 053 054 /** 055 * Create a JFilterInput without a filter. 056 * 057 * <p>This will then behave like a normal JTextField. 058 * </p> 059 */ 060 public JFilterInput() { 061 this("", JTextField.LEFT, null); 062 } 063 064 /** 065 * Create a JFilterInput with the given filter. 066 * 067 * @param filter The filter to apply on this. 068 */ 069 public JFilterInput(InputFilter filter) { 070 this("", JTextField.LEFT, filter); 071 } 072 073 /** 074 * Create a JFilterInput with the given parameters. 075 * 076 * @param text The default text. 077 * @param type The input type (text alignment). 078 * @param filter The filter to apply on this. 079 */ 080 public JFilterInput(String text, int type, InputFilter filter) { 081 super(text, type); 082 m_ifFilter = filter; 083 addFocusListener(new FocusListener() { 084 public void focusGained(FocusEvent e) { 085 // does nothing at the current implementation. 086 } 087 088 public void focusLost(FocusEvent e) { 089 if (m_ifFilter != null) { 090 try { 091 boolean oldForceAllow = m_bForceAllow; 092 m_bForceAllow = true; 093 setText(m_ifFilter.validExit(getText(0, getDocument().getLength()))); 094 m_bForceAllow = oldForceAllow; 095 } catch (BadLocationException ble) { } 096 } 097 098 } 099 }); 100 } 101 102 /** 103 * Set the InputFilter that should be used from now on. 104 * 105 * <p><b>Note:</b> This will simply set the new filter reference. The input 106 * already given will be in no way processed or validated.</p> 107 * 108 * @param filter 109 */ 110 public void setFilter(InputFilter filter) { 111 m_ifFilter = filter; 112 } 113 114 /** 115 * Create and return the input fields document. 116 */ 117 protected Document createDefaultModel() { 118 return new PlainDocument() { 119 private static final long serialVersionUID = 3257289110602724153L; 120 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { 121 String sText = getText(0, getLength()); 122 if (sText == null) { 123 sText = ""; 124 offs = 0; 125 } 126 sText = new StringBuffer(sText).insert(offs, str).toString(); 127 128 if (m_bForceAllow || m_ifFilter == null || m_ifFilter.allowEditing(sText)) { 129 super.insertString(offs, str, a); 130 } 131 } 132 133 public void remove(int offs, int len) throws BadLocationException { 134 String sText = getText(0, getLength()); 135 136 if (sText == null) { 137 return; 138 } 139 140 sText = new StringBuffer(sText).delete(offs, offs + len).toString(); 141 if (m_bForceAllow || m_ifFilter == null || m_ifFilter.allowEditing(sText)) { 142 super.remove(offs, len); 143 } 144 } 145 }; 146 } 147 148 /** 149 * Enable or disable the filter. If the filter is disabled, every kind of input 150 * will be accepted. This is mainly for internal use in cases it's useful. 151 * 152 * @param en Whether (<code>true</code>) or not (<code>false</code>) to enable 153 * the filter. 154 */ 155 protected void setFilterEnabled(boolean en) { 156 m_bForceAllow = !en; 157 } 158 }