KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > junit > ClassNameTextField


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 2004-2005 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.junit;
21
22 import javax.swing.JTextField JavaDoc;
23 import javax.swing.event.ChangeEvent JavaDoc;
24 import javax.swing.event.ChangeListener JavaDoc;
25 import javax.swing.event.DocumentEvent JavaDoc;
26 import javax.swing.event.DocumentListener JavaDoc;
27 import javax.swing.text.BadLocationException JavaDoc;
28
29 /**
30  * Text-field that validates whether its text is a valid class name (may be
31  * package-classified or not) and may notify a registered listener of status
32  * changes (empty/valid/invalid).
33  * <p>
34  * To start listening on validity of the entered class name, register
35  * a <code>ChangeListener</code>.
36  * <p>
37  * Example:
38  * <pre><code> ...
39  * final ClassNameTextField tfClassName = new ClassNameTextField();
40  * tfClassName.setChangeListener(new ChangeListener() {
41  * public void stateChanged(ChangeEvent e) {
42  * int state = tfClassName.getState();
43  * switch (state) {
44  * case ClassNameTextField.STATUS_EMPTY:
45  * System.out.println("Empty class name!");
46  * break;
47  * case ClassNameTextField.STATUS_INVALID:
48  * System.out.println("Invalid class name!");
49  * break;
50  * case ClassNameTextField.VALID:
51  * System.out.println("Thank you!");
52  * break;
53  * }
54  * }
55  * });
56  * panel.add(tfClassName);
57  * ...
58  * </code></pre>
59  *
60  * @author Marian Petras
61  */

62 public final class ClassNameTextField extends JTextField JavaDoc {
63     
64     /** status: the class name is valid */
65     public static final int STATUS_VALID = 0;
66     /** status: the class name is empty */
67     public static final int STATUS_EMPTY = 1;
68     /** status: the class name is not valid */
69     public static final int STATUS_INVALID = 2;
70     /** */
71     public static final int STATUS_VALID_NOT_DEFAULT = 3;
72
73     /**
74      * internal status - when the text is empty or when it ends with a dot
75      * (<code>'.'</code>) and appending one legal character to it would make
76      * it a legal class name
77      */

78     static final int STATUS_BEFORE_PART = 3;
79     
80     /** */
81     private TextListener documentListener;
82     /** */
83     private int externalStatus = 0;
84     /** */
85     private boolean externalStatusValid = false;
86     /** */
87     private ChangeListener JavaDoc changeListener;
88     /** */
89     private ChangeEvent JavaDoc changeEvent;
90     /** */
91     private String JavaDoc defaultText;
92
93     /**
94      * Creates an empty text-field.
95      */

96     public ClassNameTextField() {
97         this((String JavaDoc) null);
98         setupDocumentListener();
99     }
100     
101     /**
102      * Creates an empty with initial text.
103      *
104      * @param text initial text of the text-field
105      * (for empty text, use <code>&quot;&quot;</code>
106      * or <code>null</code>)
107      */

108     public ClassNameTextField(String JavaDoc text) {
109         super(text == null ? "" : text); //NOI18N
110
setupDocumentListener();
111     }
112     
113     /**
114      */

115     public void setDefaultText(String JavaDoc defaultText) {
116         if ((defaultText == null) && (this.defaultText == null)
117              || (defaultText != null) && defaultText.equals(this.defaultText)) {
118             return;
119         }
120         
121         this.defaultText = defaultText;
122         
123         if ((defaultText != null)
124                 || (externalStatusValid
125                     && (externalStatus == STATUS_VALID_NOT_DEFAULT))) {
126             statusMaybeChanged();
127         }
128     }
129     
130     /**
131      */

132     private void setupDocumentListener() {
133         getDocument().addDocumentListener(
134                 documentListener = new TextListener());
135     }
136
137     /**
138      * Determines internal status for the current text.
139      * The status may be one of
140      * <code>STATUS_VALID</code>, <code>STATUS_INVALID</code> and
141      * <code>STATUS_BEFORE_PART</code>.
142      *
143      * @return status for the current text
144      */

145     int determineStatus() {
146         String JavaDoc text = getText();
147         
148         int status = STATUS_BEFORE_PART;
149         char[] chars = text.toCharArray();
150         for (int i = 0; i < chars.length; i++) {
151             char c = chars[i];
152             switch (status) {
153                 case STATUS_BEFORE_PART:
154                     if (!Character.isJavaIdentifierStart(c)) {
155                         return STATUS_INVALID;
156                     }
157                     status = STATUS_VALID;
158                     break;
159                 case STATUS_VALID:
160                     if (c == '.') {
161                         status = STATUS_BEFORE_PART;
162                     } else if (Character.isJavaIdentifierPart(c)) {
163                         status = STATUS_VALID;
164                     } else {
165                         return STATUS_INVALID;
166                     }
167                     break;
168                 default:
169                     assert false;
170             }
171         }
172         return status;
173     }
174     
175     /**
176      * Returns status of the text.
177      *
178      * @return one of <code>STATUS_EMPTY</code>,
179      * <code>STATUS_VALID</code>,
180      * <code>STATUS_INVALID</code>
181      */

182     public int getStatus() {
183         if (!externalStatusValid) {
184             updateExternalStatus();
185         }
186         return externalStatus;
187     }
188
189     /**
190      */

191     private void updateExternalStatus() {
192         assert externalStatusValid == false;
193
194         int internalStatus = documentListener.status;
195         switch (internalStatus) {
196             case STATUS_VALID:
197                 externalStatus = (defaultText == null)
198                                         || defaultText.equals(getText())
199                                  ? STATUS_VALID
200                                  : STATUS_VALID_NOT_DEFAULT;
201                 break;
202             case STATUS_BEFORE_PART:
203                 externalStatus = (getText().length() == 0) ? STATUS_EMPTY
204                                                            : STATUS_INVALID;
205                 break;
206             case STATUS_INVALID:
207                 externalStatus = STATUS_INVALID;
208                 break;
209             default:
210                 assert false;
211                 externalStatus = STATUS_INVALID;
212                 break;
213         }
214         externalStatusValid = true;
215     }
216     
217     /**
218      * Registers a change listener.
219      * The listener will be notified each time status of this text-field
220      * (valid/invalid/empty) changes.
221      *
222      * <!-- PENDING: The listener cannot be unregistered. -->
223      * <!-- PENDING: Only one listener can be registered at a time. -->
224      *
225      * @param listener change listener to be registered
226      * @see #getStatus
227      */

228     public void setChangeListener(ChangeListener JavaDoc listener) {
229         changeEvent = new ChangeEvent JavaDoc(this);
230         this.changeListener = listener;
231     }
232     
233     /**
234      */

235     private void statusMaybeChanged() {
236         externalStatusValid = false;
237
238         if (changeListener != null) {
239             final int prevExternalStatus = externalStatus;
240             externalStatus = getStatus();
241             if (externalStatus != prevExternalStatus) {
242                 changeListener.stateChanged(changeEvent);
243             }
244         }
245     }
246     
247     /**
248      */

249     private final class TextListener implements DocumentListener JavaDoc {
250
251         /** internal status of the class name */
252         private int status;
253         /** */
254         private int length;
255
256         /**
257          */

258         public TextListener() {
259             status = determineStatus();
260             length = ClassNameTextField.this.getText().length();
261         }
262
263         /**
264          */

265         public void changedUpdate(DocumentEvent JavaDoc documentEvent) {
266             length = documentEvent.getDocument().getLength();
267             int newStatus = determineStatus();
268
269             if (newStatus != status) {
270                 status = newStatus;
271                 statusMaybeChanged();
272             } else if ((status == STATUS_VALID) && (defaultText != null)) {
273                 statusMaybeChanged(); //maybe default <--> not default
274
}
275
276             assert length == getDocument().getLength();
277         }
278
279         /**
280          */

281         public void insertUpdate(DocumentEvent JavaDoc documentEvent) {
282             int newStatus;
283             boolean wasEmpty = (length == 0);
284
285             if (documentEvent.getLength() != 1
286                     || (documentEvent.getOffset() != length)) {
287                 length += documentEvent.getLength();
288                 newStatus = determineStatus();
289             } else {
290                 char c;
291
292                 /* now we know that a single character was appended */
293                 try {
294                     c = documentEvent.getDocument().getText(length++, 1)
295                         .charAt(0);
296                     switch (status) {
297                         case STATUS_VALID:
298                             newStatus = (c == '.')
299                                         ? newStatus = STATUS_BEFORE_PART
300                                         : (Character.isJavaIdentifierPart(c))
301                                           ? STATUS_VALID
302                                           : STATUS_INVALID;
303                             break;
304                         case STATUS_BEFORE_PART:
305                             newStatus = (Character.isJavaIdentifierStart(c))
306                                         ? STATUS_VALID
307                                         : STATUS_INVALID;
308                             break;
309                         case STATUS_INVALID:
310                             newStatus = determineStatus();
311                             break;
312                         default:
313                             assert false;
314                             newStatus = determineStatus();
315                             break;
316                     }
317                 } catch (BadLocationException JavaDoc ex) {
318                     assert false;
319                     
320                     length = documentEvent.getDocument().getLength();
321                     newStatus = determineStatus();
322                 }
323             }
324
325             /*
326              * We must handle addition of a text to an empty text field
327              * specially because it may not change internal state
328              * (if it becomes STATUS_BEFORE_PART after the addition).
329              */

330             if ((newStatus != status) || wasEmpty) {
331                 status = newStatus;
332                 statusMaybeChanged();
333             } else if ((status == STATUS_VALID) && (defaultText != null)) {
334                 statusMaybeChanged(); //maybe default <--> not default
335
}
336
337             assert length == getDocument().getLength();
338         }
339
340         /**
341          */

342         public void removeUpdate(DocumentEvent JavaDoc documentEvent) {
343             int newStatus;
344
345             if (documentEvent.getLength() != 1
346                     || (documentEvent.getOffset() != (length - 1))) {
347                 length -= documentEvent.getLength();
348                 newStatus = determineStatus();
349             } else {
350
351                 /*
352                  * now we know that a single character was deleted
353                  * from the end
354                  */

355                 length--;
356                 switch (status) {
357                     case STATUS_VALID:
358                         try {
359                             newStatus = ((length == 0)
360                                          || (documentEvent.getDocument()
361                                              .getText(length - 1, 1))
362                                              .charAt(0) == '.')
363                                         ? STATUS_BEFORE_PART
364                                         : STATUS_VALID;
365                         } catch (BadLocationException JavaDoc ex) {
366                             assert false;
367                             
368                             newStatus = determineStatus();
369                             length = documentEvent.getDocument().getLength();
370                         }
371                         break;
372                     case STATUS_BEFORE_PART:
373                         newStatus = STATUS_VALID; //trailing dot deleted
374
break;
375                     case STATUS_INVALID:
376                         newStatus = (length == 0) ? STATUS_VALID
377                                                   : determineStatus();
378                         break;
379                     default:
380                         assert false;
381                         newStatus = determineStatus();
382                         break;
383                 }
384             }
385
386                 
387             /*
388              * We must handle deletion of the whole text specially because
389              * it may not change internal state (if it was STATUS_BEFORE_PART
390              * before the deletion).
391              */

392             if ((newStatus != status) || (length == 0)) {
393                 status = newStatus;
394                 statusMaybeChanged();
395             } else if ((status == STATUS_VALID) && (defaultText != null)) {
396                 statusMaybeChanged(); //maybe default <--> not default
397
}
398
399             assert length == getDocument().getLength();
400         }
401
402     }
403     
404 }
405
Popular Tags