1 /*
2 * The contents of this file are subject to the BT "ZEUS" Open Source
3 * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file
4 * except in compliance with the Licence. You may obtain a copy of the Licence
5 * from $ZEUS_INSTALL/licence.html or alternatively from
6 * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7 *
8 * Except as stated in Clause 7 of the Licence, software distributed under the
9 * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or
10 * implied. See the Licence for the specific language governing rights and
11 * limitations under the Licence.
12 *
13 * The Original Code is within the package zeus.*.
14 * The Initial Developer of the Original Code is British Telecommunications
15 * public limited company, whose registered office is at 81 Newgate Street,
16 * London, EC1A 7AJ, England. Portions created by British Telecommunications
17 * public limited company are Copyright 1996-9. All Rights Reserved.
18 *
19 * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20 */
21 
22 package figtree.ui.components;
23 
24 import javax.swing.*;
25 import javax.swing.event.*;
26 import javax.swing.text.AttributeSet;
27 import javax.swing.text.BadLocationException;
28 import javax.swing.text.Document;
29 import javax.swing.text.PlainDocument;
30 import java.awt.*;
31 import java.awt.event.FocusEvent;
32 import java.awt.event.FocusListener;
33 
34 /**
35  *
36  * @version $Id$
37  *
38  * $HeadURL$
39  *
40  * $LastChangedBy$
41  * $LastChangedDate$
42  * $LastChangedRevision$
43  */
44 public class RealNumberField extends JTextField
45         implements FocusListener, DocumentListener {
46 
47     protected static char MINUS = '-';
48     protected static char PERIOD = '.';
49     protected EventListenerList changeListeners = new EventListenerList();
50     protected double min;
51     protected double max;
52     protected boolean range_check = false;
53     protected boolean range_checked = false;
54 
RealNumberField()55     public RealNumberField() {
56         super();
57     }
58 
RealNumberField(double min, double max)59     public RealNumberField(double min, double max) {
60         this();
61         this.min = min;
62         this.max = max;
63         range_check = true;
64         this.addFocusListener(this);
65     }
66 
focusGained(FocusEvent evt)67     public void focusGained(FocusEvent evt) {
68     }
69 
focusLost(FocusEvent evt)70     public void focusLost(FocusEvent evt) {
71         if (range_check && !range_checked) {
72             range_checked = true;
73             try {
74                 double value = (Double.valueOf(getText())).doubleValue();
75                 if (value < min || value > max) {
76                     errorMsg();
77                     return;
78                 }
79             } catch (NumberFormatException e) {
80                 errorMsg();
81                 return;
82             }
83         }
84     }
85 
setText(Double obj)86     public void setText(Double obj) {
87         setText(obj.toString());
88     }
89 
setText(Integer obj)90     public void setText(Integer obj) {
91         setText(obj.toString());
92     }
93 
setText(Long obj)94     public void setText(Long obj) {
95         setText(obj.toString());
96     }
97 
errorMsg()98     protected void errorMsg() {
99         JOptionPane.showMessageDialog(this,
100                 "Illegal entry\nValue must be between " + min + " and " +
101                 max + " inclusive", "Error", JOptionPane.ERROR_MESSAGE);
102     }
103 
setRange(double min, double max)104     public void setRange(double min, double max) {
105         this.min = min;
106         this.max = max;
107         range_check = true;
108     }
109 
setValue(double value)110     public void setValue(double value) {
111         if (range_check) {
112             if (value < min || value > max) {
113                 errorMsg();
114                 return;
115             }
116         }
117         setText(Double.toString(value));
118     }
119 
getValue()120     public Double getValue() {
121         try {
122             return new Double(getText());
123         } catch (NumberFormatException e) {
124             return null;
125         }
126     }
127 
getValue(double def)128     public Double getValue(double def) {
129         try {
130             return new Double(getText());
131         } catch (NumberFormatException e) {
132             return new Double(def);
133         }
134     }
135 
createDefaultModel()136     protected Document createDefaultModel() {
137         Document doc = new RealNumberFieldDocument();
138         doc.addDocumentListener(this);
139         return doc;
140     }
141 
insertUpdate(DocumentEvent e)142     public void insertUpdate(DocumentEvent e) {
143         range_checked = false;
144         fireChanged();
145     }
146 
removeUpdate(DocumentEvent e)147     public void removeUpdate(DocumentEvent e) {
148         range_checked = false;
149         fireChanged();
150     }
151 
changedUpdate(DocumentEvent e)152     public void changedUpdate(DocumentEvent e) {
153         range_checked = false;
154         fireChanged();
155     }
156 
157     static char[] numberSet = {
158         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
159     };
160 
161     class RealNumberFieldDocument extends PlainDocument {
insertString(int offs, String str, AttributeSet a)162         public void insertString(int offs, String str, AttributeSet a)
163                 throws BadLocationException {
164 
165             if (str == null) return;
166             str = str.trim();
167 
168             int length = getLength();
169             String buf = getText(0, offs) + str + getText(offs, length - offs);
170             buf = buf.trim().toUpperCase();
171             char[] array = buf.toCharArray();
172 
173             if (array.length > 0) {
174                 if (array[0] != MINUS && !member(array[0], numberSet) &&
175                         array[0] != PERIOD) {
176                     Toolkit.getDefaultToolkit().beep();
177                     return;
178                 }
179             }
180 
181             boolean period_found = (array.length > 0 && array[0] == PERIOD);
182             boolean exponent_found =  false;
183             int exponent_index = -1;
184             boolean exponent_sign_found =  false;
185 
186             for (int i = 1; i < array.length; i++) {
187                 if (!member(array[i], numberSet)) {
188                     if (!period_found && array[i] == PERIOD) {
189                         period_found = true;
190                     } else if (!exponent_found && array[i] == 'E') {
191                         exponent_found = true;
192                         exponent_index = i;
193                     } else if (exponent_found && i == (exponent_index + 1) && !exponent_sign_found && array[i] == '-') {
194                         exponent_sign_found = true;
195                     } else {
196                         Toolkit.getDefaultToolkit().beep();
197                         return;
198                     }
199                 }
200             }
201             super.insertString(offs, str, a);
202         }
203     }
204 
member(char item, char[] array)205     static boolean member(char item, char[] array) {
206         for (int i = 0; i < array.length; i++)
207             if (array[i] == item) return true;
208         return false;
209     }
210     //------------------------------------------------------------------------
211     // Event Methods
212     //------------------------------------------------------------------------
213 
addChangeListener(ChangeListener x)214     public void addChangeListener(ChangeListener x) {
215         changeListeners.add(ChangeListener.class, x);
216     }
217 
removeChangeListener(ChangeListener x)218     public void removeChangeListener(ChangeListener x) {
219         changeListeners.remove(ChangeListener.class, x);
220     }
221 
fireChanged()222     protected void fireChanged() {
223         ChangeEvent c = new ChangeEvent(this);
224         Object[] listeners = changeListeners.getListenerList();
225         for (int i = listeners.length - 2; i >= 0; i -= 2) {
226             if (listeners[i] == ChangeListener.class) {
227                 ChangeListener cl = (ChangeListener) listeners[i + 1];
228                 cl.stateChanged(c);
229             }
230         }
231     }
232 }
233