Source code: org/maloi/evolvo/gui/DoubleField.java
1 /* Evolvo - Image Generator
2 * Copyright (C) 2000 Andrew Molloy
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /**
20 * $Id: DoubleField.java,v 1.2 2002/10/07 15:20:21 maloi Exp $
21 */
22
23 package org.maloi.evolvo.gui;
24
25 import java.awt.event.ActionEvent;
26 import java.awt.event.ActionListener;
27 import java.awt.event.FocusEvent;
28 import java.awt.event.FocusListener;
29
30 import javax.swing.JTextField;
31 import javax.swing.event.ChangeEvent;
32 import javax.swing.event.ChangeListener;
33 import javax.swing.text.AttributeSet;
34 import javax.swing.text.BadLocationException;
35 import javax.swing.text.Document;
36 import javax.swing.text.PlainDocument;
37
38 /**
39 * Extends JTextField, allowing only numbers to be entered.
40 * These numbers may be floating point (double, specifically), but are
41 * restricted to a specified range.
42 */
43 public class DoubleField
44 extends JTextField
45 implements ActionListener, ChangeListener, FocusListener
46 {
47 /** Range model used to determine valid values for the text field. */
48 DoubleBoundedRangeModel dbrm;
49 int precision;
50
51 /** Default constructor. */
52 public DoubleField()
53 {
54 this(0.0, 0.0, 0.0, 1.0, 4, 6);
55 }
56
57 /** Class constuctor that takes DoubleBoundedRandeModel's parameters
58 * individually, and a column width.
59 */
60 public DoubleField(
61 double v,
62 double e,
63 double min,
64 double max,
65 int p,
66 int cols)
67 {
68 this(new DoubleBoundedRangeModel(v, e, min, max, p), cols);
69
70 setPrecision(p);
71 }
72
73 /** Class constuctor that takes DoubleBoundedRandeModel's parameters
74 * individually, setting a default column width.
75 */
76 public DoubleField(double v, double e, double min, double max, int p)
77 {
78 this(new DoubleBoundedRangeModel(v, e, min, max, p), 6);
79
80 setPrecision(p);
81 }
82
83 /** Class constructor that takes a DoubleBoundedRangeModel and sets the
84 * column with to a default value.
85 */
86 public DoubleField(DoubleBoundedRangeModel dm)
87 {
88 this(dm, 6);
89 }
90
91 /** Class constructor which takes a DoubleBoundedRangeModel, and a column
92 * width.
93 */
94 public DoubleField(DoubleBoundedRangeModel dm, int cols)
95 {
96 super(cols);
97 dbrm = dm;
98 addActionListener(this);
99 addChangeListener(this);
100
101 setPrecision(dbrm.getPrecision());
102 setFieldText(Double.toString(dbrm.getDoubleValue()));
103
104 addFocusListener(this);
105 }
106
107 /** Creates a new DoubleDocument document model. */
108 protected Document createDefaultModel()
109 {
110 return new DoubleDocument();
111 }
112
113 /** Handles all recieved ActionEvents. */
114 public void actionPerformed(ActionEvent e)
115 {
116 try
117 {
118 setValue(Double.parseDouble(getText()));
119 // Set the value to number in the text field.
120 }
121 catch (NumberFormatException ex)
122 {
123 select(0, getText().length());
124 // If the text field does not contain a valid number, reject the input and select all the text.
125 }
126 }
127
128 public void setFieldText(String s)
129 {
130 int end = s.indexOf(".");
131
132 if (end == -1)
133 {
134 end = s.length();
135 }
136 else
137 {
138 end += precision;
139
140 if (precision != 0)
141 {
142 end++;
143 }
144
145 if (end > s.length())
146 {
147 end = s.length();
148 }
149 }
150
151 s = s.substring(0, end);
152
153 setText(s);
154 }
155
156 /** Handles all recieved ChangeEvents. */
157 public void stateChanged(ChangeEvent e)
158 {
159 setValue(dbrm.getDoubleValue());
160
161 setFieldText(Double.toString(dbrm.getDoubleValue()));
162 }
163
164 /** Returns the current value of the text field as a double. */
165 public double getValue()
166 {
167 return dbrm.getDoubleValue();
168 }
169
170 /** Sets the value of the text field from a double. */
171 public void setValue(double newValue)
172 {
173 double oldValue = dbrm.getDoubleValue();
174 dbrm.setDoubleValue(newValue);
175 newValue = dbrm.getDoubleValue();
176
177 setFieldText(Double.toString(newValue));
178
179 select(0, getText().length()); // Select the entire text field.
180
181 firePropertyChange("value", oldValue, dbrm.getDoubleValue());
182 }
183
184 /** Adds a ChangeListener. */
185 public void addChangeListener(ChangeListener l)
186 {
187 dbrm.addChangeListener(l);
188 }
189
190 /** Removes a ChangeListener. */
191 public void removeChangeListener(ChangeListener l)
192 {
193 dbrm.removeChangeListener(l);
194 }
195
196 /** Defines a document model that restricts input to characters which may
197 * be used to define a double.
198 */
199 static class DoubleDocument extends PlainDocument
200 {
201 /** The acceptable characters. */
202 byte[] validChars = new String("eE-+.0123456789").getBytes();
203 /** The number of acceptable characters. */
204 int vcLength = validChars.length;
205
206 /** Insert the given String into the document iff it is valid.
207 * @throws BadLocationException
208 */
209 public void insertString(int offset, String str, AttributeSet a)
210 throws BadLocationException
211 {
212 byte[] strArray = str.getBytes();
213 boolean valid = true;
214
215 for (int strIndex = 0; strIndex < strArray.length; strIndex++)
216 {
217 boolean internalValid = false;
218 for (int vcIndex = 0; vcIndex < vcLength; vcIndex++)
219 {
220 if (strArray[strIndex] == validChars[vcIndex])
221 {
222 internalValid = true;
223 vcIndex = vcLength;
224 }
225 }
226 if (internalValid == false)
227 {
228 valid = false;
229 strIndex = strArray.length;
230 }
231 }
232 if (!valid)
233 {
234 return;
235 }
236 super.insertString(offset, str, a);
237 }
238 }
239
240 public void setPrecision(int p)
241 {
242 precision = p;
243
244 dbrm.setPrecision(p);
245 }
246
247 public void focusGained(FocusEvent e)
248 {
249 }
250
251 public void focusLost(FocusEvent e)
252 {
253 // Set our value when we lose focus
254 setValue(Double.parseDouble(getText()));
255 }
256 }