001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.component; 020 021import icy.util.StringUtil; 022 023import java.awt.event.ActionEvent; 024import java.awt.event.ActionListener; 025import java.awt.event.FocusEvent; 026import java.awt.event.FocusListener; 027import java.awt.event.KeyEvent; 028import java.text.Format; 029import java.util.EventListener; 030 031import javax.swing.JFormattedTextField; 032import javax.swing.event.DocumentEvent; 033import javax.swing.event.DocumentListener; 034 035/** 036 * IcyTextField extends JFormattedTextField and provide easier text change handling. 037 * 038 * @author Stephane 039 */ 040public class IcyTextField extends JFormattedTextField implements DocumentListener, ActionListener, FocusListener 041{ 042 /** 043 * 044 */ 045 private static final long serialVersionUID = 4294607311366304781L; 046 047 public interface TextChangeListener extends EventListener 048 { 049 public void textChanged(IcyTextField source, boolean validate); 050 } 051 052 // internals 053 /** 054 * @deprecated Don't use this property. 055 */ 056 @Deprecated 057 protected boolean consumeCharKeyPressEvent; 058 protected boolean changed; 059 060 /** 061 * Creates a <code>IcyTextField</code> with no <code>AbstractFormatterFactory</code>. Use 062 * <code>setMask</code> or <code>setFormatterFactory</code> to configure the 063 * <code>JFormattedTextField</code> to edit a particular type of 064 * value. 065 */ 066 public IcyTextField() 067 { 068 super(); 069 070 init(); 071 } 072 073 /** 074 * Creates a <code>IcyTextField</code> with the specified <code>AbstractFormatter</code>. The 075 * <code>AbstractFormatter</code> is placed in an <code>AbstractFormatterFactory</code>. 076 * 077 * @param formatter 078 * AbstractFormatter to use for formatting. 079 */ 080 public IcyTextField(AbstractFormatter formatter) 081 { 082 super(formatter); 083 084 init(); 085 } 086 087 /** 088 * Creates a <code>IcyTextField</code>. <code>format</code> is 089 * wrapped in an appropriate <code>AbstractFormatter</code> which is 090 * then wrapped in an <code>AbstractFormatterFactory</code>. 091 * 092 * @param format 093 * Format used to look up an AbstractFormatter 094 */ 095 public IcyTextField(Format format) 096 { 097 super(format); 098 099 init(); 100 } 101 102 /** 103 * Creates a IcyTextField with the specified value. This will 104 * create an <code>AbstractFormatterFactory</code> based on the 105 * type of <code>value</code>. 106 * 107 * @param value 108 * Initial value for the IcyTextField 109 */ 110 public IcyTextField(Object value) 111 { 112 super(value); 113 114 init(); 115 } 116 117 protected void init() 118 { 119 changed = false; 120 consumeCharKeyPressEvent = false; 121 122 getDocument().addDocumentListener(this); 123 addActionListener(this); 124 addFocusListener(this); 125 } 126 127 protected void internalTextChanged(boolean validate) 128 { 129 // simple text change 130 if (!validate) 131 { 132 // keep mark of text change 133 changed = true; 134 textChanged(false); 135 } 136 else 137 { 138 // previous text change 139 if (changed) 140 { 141 textChanged(true); 142 changed = false; 143 } 144 } 145 } 146 147 protected void textChanged(boolean validate) 148 { 149 fireTextChanged(validate); 150 } 151 152 protected void fireTextChanged(boolean validate) 153 { 154 for (TextChangeListener listener : listenerList.getListeners(TextChangeListener.class)) 155 listener.textChanged(this, validate); 156 } 157 158 /** 159 * Force the field to pass to unchanged state (after a {@link #setText(String)} for instance)<br> 160 * so it won't generate further <code>textChanged</code> event. 161 */ 162 public void setUnchanged() 163 { 164 changed = false; 165 } 166 167 public void addTextChangeListener(TextChangeListener listener) 168 { 169 listenerList.add(TextChangeListener.class, listener); 170 } 171 172 public void removeTextChangeListener(TextChangeListener listener) 173 { 174 listenerList.remove(TextChangeListener.class, listener); 175 } 176 177 /** 178 * @deprecated Should not be used (keep it to false) 179 */ 180 @Deprecated 181 public void setConsumeCharKeyPressEvent(boolean consumeCharKeyPressEvent) 182 { 183 this.consumeCharKeyPressEvent = consumeCharKeyPressEvent; 184 } 185 186 /** 187 * @deprecated Should not be used. 188 */ 189 @Deprecated 190 public boolean getConsumeCharKeyPressEvent() 191 { 192 return consumeCharKeyPressEvent; 193 } 194 195 @Override 196 protected void processComponentKeyEvent(KeyEvent e) 197 { 198 super.processComponentKeyEvent(e); 199 200 if (consumeCharKeyPressEvent) 201 { 202 final char c = e.getKeyChar(); 203 204 // consume KEY_PRESSED character event 205 if ((e.getID() == KeyEvent.KEY_PRESSED) && Character.isDefined(c) && !Character.isISOControl(c)) 206 e.consume(); 207 } 208 } 209 210 @Override 211 public void setText(String t) 212 { 213 if (StringUtil.equals(t, getText(), false)) 214 return; 215 216 super.setText(t); 217 218 // validate change 219 internalTextChanged(true); 220 } 221 222 @Override 223 public void changedUpdate(DocumentEvent e) 224 { 225 internalTextChanged(false); 226 } 227 228 @Override 229 public void insertUpdate(DocumentEvent e) 230 { 231 internalTextChanged(false); 232 } 233 234 @Override 235 public void removeUpdate(DocumentEvent e) 236 { 237 internalTextChanged(false); 238 } 239 240 @Override 241 public void actionPerformed(ActionEvent e) 242 { 243 internalTextChanged(true); 244 } 245 246 @Override 247 public void focusGained(FocusEvent e) 248 { 249 // nothing to do here 250 } 251 252 @Override 253 public void focusLost(FocusEvent e) 254 { 255 internalTextChanged(true); 256 } 257}