Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libUI / src / org / gvsig / gui / beans / swing / ValidatingTextField.java @ 11858

History | View | Annotate | Download (13.9 KB)

1
/*
2
 * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
3
 * for visualizing and manipulating spatial features with geometry and attributes.
4
 *
5
 * Copyright (C) 2003 Vivid Solutions
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
 *
21
 * For more information, contact:
22
 *
23
 * Vivid Solutions
24
 * Suite #1A
25
 * 2328 Government Street
26
 * Victoria BC  V8T 5G5
27
 * Canada
28
 *
29
 * (250)385-6040
30
 * www.vividsolutions.com
31
 */
32
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
33
 *
34
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
35
 *
36
 * This program is free software; you can redistribute it and/or
37
 * modify it under the terms of the GNU General Public License
38
 * as published by the Free Software Foundation; either version 2
39
 * of the License, or (at your option) any later version.
40
 *
41
 * This program is distributed in the hope that it will be useful,
42
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44
 * GNU General Public License for more details.
45
 *
46
 * You should have received a copy of the GNU General Public License
47
 * along with this program; if not, write to the Free Software
48
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
49
 *
50
 * For more information, contact:
51
 *
52
 *  Generalitat Valenciana
53
 *   Conselleria d'Infraestructures i Transport
54
 *   Av. Blasco Ib??ez, 50
55
 *   46010 VALENCIA
56
 *   SPAIN
57
 *
58
 *      +34 963862235
59
 *   gvsig@gva.es
60
 *      www.gvsig.gva.es
61
 *
62
 *    or
63
 *
64
 *   IVER T.I. S.A
65
 *   Salamanca 50
66
 *   46005 Valencia
67
 *   Spain
68
 *
69
 *   +34 963163400
70
 *   dac@iver.es
71
 */
72
package org.gvsig.gui.beans.swing;
73

    
74
import java.awt.Component;
75
import java.awt.event.FocusAdapter;
76
import java.awt.event.FocusEvent;
77

    
78
import javax.swing.JOptionPane;
79
import javax.swing.JTextField;
80
import javax.swing.text.AttributeSet;
81
import javax.swing.text.BadLocationException;
82
import javax.swing.text.PlainDocument;
83

    
84
import org.gvsig.gui.beans.Messages;
85

    
86
import junit.framework.Assert;
87

    
88

    
89
/**
90
 * Prevents the user from entering invalid data.
91
 */
92
public class ValidatingTextField extends JTextField {
93
    public static final Validator LONG_VALIDATOR = new ValidatingTextField.Validator() {
94
            public boolean isValid(String text) {
95
                try {
96
                    Long.parseLong(text.trim());
97

    
98
                    return true;
99
                } catch (NumberFormatException e) {
100
                    return false;
101
                }
102
            }
103
        };
104

    
105
    /**
106
     * Prevents the user from entering invalid integer.
107
     */
108
    public static final Validator INTEGER_VALIDATOR = new ValidatingTextField.Validator() {
109
            public boolean isValid(String text) {
110
                try {
111
                    Integer.parseInt(text.trim());
112

    
113
                    return true;
114
                } catch (NumberFormatException e) {
115
                    return false;
116
                }
117
            }
118
        };
119

    
120
    /**
121
     * Prevents the user from entering invalid double.
122
     */
123
    public static final Validator DOUBLE_VALIDATOR = new ValidatingTextField.Validator() {
124
            public boolean isValid(String text) {
125
                try {
126
                    //Add "0" so user can type "-" [Jon Aquino]
127
                    Double.parseDouble(text.trim() + "0");
128

    
129
                    return true;
130
                } catch (NumberFormatException e) {
131
                    return false;
132
                }
133
            }
134
        };
135

    
136
    /**
137
     * Cleaner that does nothing.
138
     */
139
    public static Cleaner DUMMY_CLEANER = new Cleaner() {
140
            public String clean(String text) {
141
                return text;
142
            }
143
        };
144

    
145
    /**
146
     * The validators allow the user to simply enter "+", "-", or ".". If the user
147
     * doesn't go any farther, this cleaner will set the text to 0, which is reasonable.
148
     */
149
    public static Cleaner NUMBER_CLEANER = new Cleaner() {
150
            public String clean(String text) {
151
                try {
152
                    Double.parseDouble(text.trim());
153

    
154
                    return text;
155
                } catch (NumberFormatException e) {
156
                    return "0";
157
                }
158
            }
159
        };
160

    
161
    /**
162
     * Validator that does nothing.
163
     */
164
    public static Validator DUMMY_VALIDATOR = new Validator() {
165
            public boolean isValid(String text) {
166
                return true;
167
            }
168
        };
169

    
170
    private Cleaner cleaner;
171

    
172
    /**
173
     * Validator that uses dummy cleaner.
174
     */
175
    public ValidatingTextField(String text, int columns,
176
        final Validator validator) {
177
        this(text, columns, LEFT, validator, DUMMY_CLEANER);
178
    }
179

    
180
    /**
181
     * Validator for text fields.
182
     */
183
    public ValidatingTextField(String text, int columns,
184
        int horizontalAlignment, final Validator validator,
185
        final Cleaner cleaner) {
186
        super(text, columns);
187
        this.cleaner = cleaner;
188
        setHorizontalAlignment(horizontalAlignment);
189
        installValidationBehavior(this, validator, cleaner);
190

    
191
        //Clean the text, mainly so that parties wishing to install a BlankCleaner
192
        //need only pass "" for the text. [Jon Aquino]
193
        setText(cleaner.clean(getText()));
194

    
195
        //Bonus: workaround for how GridBagLayout shrinks components to
196
        //minimum sizes if it can't accomodate their preferred sizes. [Jon Aquino]
197
        setMinimumSize(getPreferredSize());
198
    }
199

    
200
    //Hopefully this will let us add validation behaviour to combo boxes. [Jon Aquino]
201
    public static void installValidationBehavior(final JTextField textField,
202
        final Validator validator, final Cleaner cleaner) {
203
        textField.setDocument(new PlainDocument() {
204
                public void insertString(int offs, String str, AttributeSet a)
205
                    throws BadLocationException {
206
                    String currentText = this.getText(0, getLength());
207
                    String beforeOffset = currentText.substring(0, offs);
208
                    String afterOffset = currentText.substring(offs,
209
                            currentText.length());
210
                    String proposedResult = beforeOffset + str + afterOffset;
211
                    if (validator.isValid(cleaner.clean(proposedResult))) {
212
                        super.insertString(offs, str, a);
213
                    }
214
                }
215

    
216
                public void remove(int offs, int len)
217
                    throws BadLocationException {
218
                    String currentText = this.getText(0, getLength());
219
                    String beforeOffset = currentText.substring(0, offs);
220
                    String afterOffset = currentText.substring(len + offs,
221
                            currentText.length());
222
                    String proposedResult = beforeOffset + afterOffset;
223
                    if (validator.isValid(cleaner.clean(proposedResult))) {
224
                        super.remove(offs, len);
225
                    }
226
                }
227
            });
228
        textField.addFocusListener(new FocusAdapter() {
229
                public void focusLost(FocusEvent e) {
230
                    textField.setText(cleaner.clean(textField.getText()));
231
                }
232
            });
233
    }
234

    
235
    public String getText() {
236
        //Focus may not be lost yet (e.g. when syncing with scrollbar) [Jon Aquino]
237
        return cleaner.clean(super.getText());
238
    }
239

    
240
    public double getDouble() {
241
        return Double.parseDouble(getText().trim());
242
    }
243

    
244
    public int getInteger() {
245
        return Integer.parseInt(getText().trim());
246
    }
247

    
248
    public static interface Validator {
249
        public boolean isValid(String text);
250
    }
251

    
252
    public static interface Cleaner {
253
        public String clean(String text);
254
    }
255

    
256
/**
257
 * Implements validator with a greater than threshold.
258
 */
259

    
260
    public static class GreaterThanValidator implements Validator {
261
        private double threshold;
262

    
263
        public GreaterThanValidator(double threshold) {
264
            this.threshold = threshold;
265
        }
266

    
267
        public boolean isValid(String text) {
268
            return Double.parseDouble(text.trim()) > threshold;
269
        }
270
    }
271
/**
272
 * Implements validator with a less than threshold.
273
 */
274

    
275
    public static class LessThanValidator implements Validator {
276
        private double threshold;
277

    
278
        public LessThanValidator(double threshold) {
279
            this.threshold = threshold;
280
        }
281

    
282
        public boolean isValid(String text) {
283
            return Double.parseDouble(text.trim()) < threshold;
284
        }
285
    }
286
/**
287
 * Implements validator with a greater than or equal to threshold.
288
 */
289

    
290
    public static class GreaterThanOrEqualValidator implements Validator {
291
        private double threshold;
292

    
293
        public GreaterThanOrEqualValidator(double threshold) {
294
            this.threshold = threshold;
295
        }
296

    
297
        public boolean isValid(String text) {
298
            return Double.parseDouble(text.trim()) >= threshold;
299
        }
300
    }
301
/**
302
 * Implements validator with a less than or equal to threshold.
303
 */
304

    
305
    public static class LessThanOrEqualValidator implements Validator {
306
        private double threshold;
307

    
308
        public LessThanOrEqualValidator(double threshold) {
309
            this.threshold = threshold;
310
        }
311

    
312
        public boolean isValid(String text) {
313
            return Double.parseDouble(text.trim()) <= threshold;
314
        }
315
    }
316

    
317
    /**
318
 * Implements cleaner which cleans up blank strings.
319
 */
320

    
321

    
322
    public static class BlankCleaner implements Cleaner {
323
        private String replacement;
324

    
325
        public BlankCleaner(String replacement) {
326
            this.replacement = replacement;
327
        }
328

    
329
        public String clean(String text) {
330
            return (text.trim().length() == 0) ? replacement : text;
331
        }
332
    }
333

    
334
    /**
335
     * Allow the user to start typing a number with "-" or "."
336
     * @author jaquino
337
     *
338
     * To change the template for this generated type comment go to
339
     * Window>Preferences>Java>Code Generation>Code and Comments
340
     */
341
    public static class NumberCleaner implements Cleaner {
342
        private String textToAppend;
343

    
344
        public NumberCleaner(String textToAppend) {
345
            this.textToAppend = textToAppend;
346
        }
347

    
348
        public String clean(String text) {
349
            if (text.trim().length() == 0) { return text; }
350
            try {
351
                Double.parseDouble(text);
352
                return text;
353
            }
354
            catch (NumberFormatException e) {
355
                return text + textToAppend;
356
            }
357
        }
358
    }
359

    
360
    public static class MinIntCleaner implements Cleaner {
361
        private int minimum;
362

    
363
        public MinIntCleaner(int minimum) {
364
            this.minimum = minimum;
365
        }
366

    
367
        public String clean(String text) {
368
                String s="";
369
                s=""+ Math.max(minimum, Integer.parseInt(text));
370
                return s;
371
        }
372
    }
373

    
374
/**
375
 * Extends CompositeValidator to validat that integers is within a set of boundary values.
376
 */
377
    public static class BoundedIntValidator extends CompositeValidator {
378
        public BoundedIntValidator(int min, int max) {
379
            super(new Validator[] {
380
                    INTEGER_VALIDATOR, new GreaterThanOrEqualValidator(min),
381
                    new LessThanOrEqualValidator(max)
382
                });
383
            Assert.assertTrue(min < max);
384
        }
385
    }
386

    
387
    public static class BoundedDoubleValidator extends CompositeValidator {
388
        public BoundedDoubleValidator(double min, boolean includeMin,
389
            double max, boolean includeMax) {
390
            super(new Validator[] {
391
                    DOUBLE_VALIDATOR,
392
                    includeMin
393
                    ? (Validator) new GreaterThanOrEqualValidator(min)
394
                    : new GreaterThanValidator(min),
395
                    includeMax ? (Validator) new LessThanOrEqualValidator(max)
396
                               : new LessThanValidator(max)
397
                });
398
            Assert.assertTrue(min < max);
399
        }
400
    }
401

    
402
    public static class MaxIntCleaner implements Cleaner {
403
        private int maximum;
404

    
405
        public MaxIntCleaner(int maximum) {
406
            this.maximum = maximum;
407
        }
408

    
409
        public String clean(String text) {
410
                String s="";
411
                s=""+ Math.min(maximum, Integer.parseInt(text));
412
                return s;
413
        }
414
    }
415
/**
416
 * Implements validator to check for more than one condition.
417
 */
418

    
419
    public static class CompositeValidator implements Validator {
420
        private Validator[] validators;
421

    
422
        public CompositeValidator(Validator[] validators) {
423
            this.validators = validators;
424
        }
425

    
426
        public boolean isValid(String text) {
427
            for (int i = 0; i < validators.length; i++) {
428
                if (!validators[i].isValid(text)) {
429
                    return false;
430
                }
431
            }
432

    
433
            return true;
434
        }
435
    }
436

    
437
    public static class CompositeCleaner implements Cleaner {
438
        private Cleaner[] cleaners;
439

    
440
        public CompositeCleaner(Cleaner[] cleaners) {
441
            this.cleaners = cleaners;
442
        }
443

    
444
        public String clean(String text) {
445
            String result = text;
446
            try{
447
                    for (int i = 0; i < cleaners.length; i++) {
448
                            result = cleaners[i].clean(result);
449
                    }
450
                }catch (NumberFormatException e) {
451
                                    JOptionPane.showMessageDialog(null, Messages.getText("numero_incorrecto"));
452
                   }
453

    
454

    
455
            return result;
456
        }
457
    }
458
}