author | cl |
Mon, 07 Oct 2013 11:34:44 -0700 | |
changeset 20458 | f2423fb3fd19 |
parent 20455 | f6f9a0c2796b |
child 21592 | da6abe91602a |
permissions | -rw-r--r-- |
2 | 1 |
/* |
7668 | 2 |
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
package javax.swing; |
|
26 |
||
3737
83fb4621a129
6824395: Several Swing core components prevent using them in wrapper classes
alexp
parents:
1639
diff
changeset
|
27 |
import sun.swing.SwingUtilities2; |
83fb4621a129
6824395: Several Swing core components prevent using them in wrapper classes
alexp
parents:
1639
diff
changeset
|
28 |
|
2 | 29 |
import java.awt.*; |
30 |
import java.awt.event.*; |
|
31 |
import java.beans.*; |
|
32 |
import javax.swing.text.*; |
|
33 |
import javax.swing.plaf.*; |
|
34 |
import javax.swing.event.*; |
|
35 |
import javax.accessibility.*; |
|
36 |
||
37 |
import java.io.ObjectOutputStream; |
|
38 |
import java.io.ObjectInputStream; |
|
39 |
import java.io.IOException; |
|
40 |
import java.io.Serializable; |
|
41 |
||
42 |
/** |
|
43 |
* <code>JTextField</code> is a lightweight component that allows the editing |
|
44 |
* of a single line of text. |
|
45 |
* For information on and examples of using text fields, |
|
46 |
* see |
|
20455
f6f9a0c2796b
8020688: Broken links in documentation at http://docs.oracle.com/javase/6/docs/api/index.
mcherkas
parents:
20157
diff
changeset
|
47 |
* <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a> |
2 | 48 |
* in <em>The Java Tutorial.</em> |
49 |
* |
|
50 |
* <p> |
|
51 |
* <code>JTextField</code> is intended to be source-compatible |
|
52 |
* with <code>java.awt.TextField</code> where it is reasonable to do so. This |
|
53 |
* component has capabilities not found in the <code>java.awt.TextField</code> |
|
54 |
* class. The superclass should be consulted for additional capabilities. |
|
55 |
* <p> |
|
56 |
* <code>JTextField</code> has a method to establish the string used as the |
|
57 |
* command string for the action event that gets fired. The |
|
58 |
* <code>java.awt.TextField</code> used the text of the field as the command |
|
59 |
* string for the <code>ActionEvent</code>. |
|
60 |
* <code>JTextField</code> will use the command |
|
61 |
* string set with the <code>setActionCommand</code> method if not <code>null</code>, |
|
62 |
* otherwise it will use the text of the field as a compatibility with |
|
63 |
* <code>java.awt.TextField</code>. |
|
64 |
* <p> |
|
65 |
* The method <code>setEchoChar</code> and <code>getEchoChar</code> |
|
66 |
* are not provided directly to avoid a new implementation of a |
|
67 |
* pluggable look-and-feel inadvertently exposing password characters. |
|
68 |
* To provide password-like services a separate class <code>JPasswordField</code> |
|
69 |
* extends <code>JTextField</code> to provide this service with an independently |
|
70 |
* pluggable look-and-feel. |
|
71 |
* <p> |
|
72 |
* The <code>java.awt.TextField</code> could be monitored for changes by adding |
|
73 |
* a <code>TextListener</code> for <code>TextEvent</code>'s. |
|
74 |
* In the <code>JTextComponent</code> based |
|
75 |
* components, changes are broadcasted from the model via a |
|
76 |
* <code>DocumentEvent</code> to <code>DocumentListeners</code>. |
|
77 |
* The <code>DocumentEvent</code> gives |
|
78 |
* the location of the change and the kind of change if desired. |
|
79 |
* The code fragment might look something like: |
|
80 |
* <pre><code> |
|
81 |
* DocumentListener myListener = ??; |
|
82 |
* JTextField myArea = ??; |
|
83 |
* myArea.getDocument().addDocumentListener(myListener); |
|
84 |
* </code></pre> |
|
85 |
* <p> |
|
86 |
* The horizontal alignment of <code>JTextField</code> can be set to be left |
|
87 |
* justified, leading justified, centered, right justified or trailing justified. |
|
88 |
* Right/trailing justification is useful if the required size |
|
89 |
* of the field text is smaller than the size allocated to it. |
|
90 |
* This is determined by the <code>setHorizontalAlignment</code> |
|
91 |
* and <code>getHorizontalAlignment</code> methods. The default |
|
92 |
* is to be leading justified. |
|
93 |
* <p> |
|
94 |
* How the text field consumes VK_ENTER events depends |
|
95 |
* on whether the text field has any action listeners. |
|
96 |
* If so, then VK_ENTER results in the listeners |
|
97 |
* getting an ActionEvent, |
|
98 |
* and the VK_ENTER event is consumed. |
|
99 |
* This is compatible with how AWT text fields handle VK_ENTER events. |
|
100 |
* If the text field has no action listeners, then as of v 1.3 the VK_ENTER |
|
101 |
* event is not consumed. Instead, the bindings of ancestor components |
|
102 |
* are processed, which enables the default button feature of |
|
103 |
* JFC/Swing to work. |
|
104 |
* <p> |
|
105 |
* Customized fields can easily be created by extending the model and |
|
106 |
* changing the default model provided. For example, the following piece |
|
107 |
* of code will create a field that holds only upper case characters. It |
|
108 |
* will work even if text is pasted into from the clipboard or it is altered via |
|
109 |
* programmatic changes. |
|
110 |
* <pre><code> |
|
111 |
||
112 |
public class UpperCaseField extends JTextField { |
|
113 |
|
|
114 |
public UpperCaseField(int cols) { |
|
115 |
super(cols); |
|
116 |
} |
|
117 |
|
|
118 |
protected Document createDefaultModel() { |
|
119 |
return new UpperCaseDocument(); |
|
120 |
} |
|
121 |
|
|
122 |
static class UpperCaseDocument extends PlainDocument { |
|
123 |
|
|
124 |
public void insertString(int offs, String str, AttributeSet a) |
|
125 |
throws BadLocationException { |
|
126 |
|
|
127 |
if (str == null) { |
|
128 |
return; |
|
129 |
} |
|
130 |
char[] upper = str.toCharArray(); |
|
20157
cafca01a8e28
8025230: [cleanup] some more javadoc formatting fixes for swing
yan
parents:
7668
diff
changeset
|
131 |
for (int i = 0; i < upper.length; i++) { |
2 | 132 |
upper[i] = Character.toUpperCase(upper[i]); |
133 |
} |
|
134 |
super.insertString(offs, new String(upper), a); |
|
135 |
} |
|
136 |
} |
|
137 |
} |
|
138 |
||
139 |
* </code></pre> |
|
140 |
* <p> |
|
141 |
* <strong>Warning:</strong> Swing is not thread safe. For more |
|
142 |
* information see <a |
|
143 |
* href="package-summary.html#threading">Swing's Threading |
|
144 |
* Policy</a>. |
|
145 |
* <p> |
|
146 |
* <strong>Warning:</strong> |
|
147 |
* Serialized objects of this class will not be compatible with |
|
148 |
* future Swing releases. The current serialization support is |
|
149 |
* appropriate for short term storage or RMI between applications running |
|
150 |
* the same version of Swing. As of 1.4, support for long term storage |
|
20458 | 151 |
* of all JavaBeans™ |
2 | 152 |
* has been added to the <code>java.beans</code> package. |
153 |
* Please see {@link java.beans.XMLEncoder}. |
|
154 |
* |
|
155 |
* @beaninfo |
|
156 |
* attribute: isContainer false |
|
157 |
* description: A component which allows for the editing of a single line of text. |
|
158 |
* |
|
159 |
* @author Timothy Prinzing |
|
160 |
* @see #setActionCommand |
|
161 |
* @see JPasswordField |
|
162 |
* @see #addActionListener |
|
163 |
*/ |
|
164 |
public class JTextField extends JTextComponent implements SwingConstants { |
|
165 |
||
166 |
/** |
|
167 |
* Constructs a new <code>TextField</code>. A default model is created, |
|
168 |
* the initial string is <code>null</code>, |
|
169 |
* and the number of columns is set to 0. |
|
170 |
*/ |
|
171 |
public JTextField() { |
|
172 |
this(null, null, 0); |
|
173 |
} |
|
174 |
||
175 |
/** |
|
176 |
* Constructs a new <code>TextField</code> initialized with the |
|
177 |
* specified text. A default model is created and the number of |
|
178 |
* columns is 0. |
|
179 |
* |
|
180 |
* @param text the text to be displayed, or <code>null</code> |
|
181 |
*/ |
|
182 |
public JTextField(String text) { |
|
183 |
this(null, text, 0); |
|
184 |
} |
|
185 |
||
186 |
/** |
|
187 |
* Constructs a new empty <code>TextField</code> with the specified |
|
188 |
* number of columns. |
|
189 |
* A default model is created and the initial string is set to |
|
190 |
* <code>null</code>. |
|
191 |
* |
|
192 |
* @param columns the number of columns to use to calculate |
|
193 |
* the preferred width; if columns is set to zero, the |
|
194 |
* preferred width will be whatever naturally results from |
|
195 |
* the component implementation |
|
196 |
*/ |
|
197 |
public JTextField(int columns) { |
|
198 |
this(null, null, columns); |
|
199 |
} |
|
200 |
||
201 |
/** |
|
202 |
* Constructs a new <code>TextField</code> initialized with the |
|
203 |
* specified text and columns. A default model is created. |
|
204 |
* |
|
205 |
* @param text the text to be displayed, or <code>null</code> |
|
206 |
* @param columns the number of columns to use to calculate |
|
207 |
* the preferred width; if columns is set to zero, the |
|
208 |
* preferred width will be whatever naturally results from |
|
209 |
* the component implementation |
|
210 |
*/ |
|
211 |
public JTextField(String text, int columns) { |
|
212 |
this(null, text, columns); |
|
213 |
} |
|
214 |
||
215 |
/** |
|
216 |
* Constructs a new <code>JTextField</code> that uses the given text |
|
217 |
* storage model and the given number of columns. |
|
218 |
* This is the constructor through which the other constructors feed. |
|
219 |
* If the document is <code>null</code>, a default model is created. |
|
220 |
* |
|
221 |
* @param doc the text storage to use; if this is <code>null</code>, |
|
222 |
* a default will be provided by calling the |
|
223 |
* <code>createDefaultModel</code> method |
|
224 |
* @param text the initial string to display, or <code>null</code> |
|
225 |
* @param columns the number of columns to use to calculate |
|
20157
cafca01a8e28
8025230: [cleanup] some more javadoc formatting fixes for swing
yan
parents:
7668
diff
changeset
|
226 |
* the preferred width >= 0; if <code>columns</code> |
2 | 227 |
* is set to zero, the preferred width will be whatever |
228 |
* naturally results from the component implementation |
|
20157
cafca01a8e28
8025230: [cleanup] some more javadoc formatting fixes for swing
yan
parents:
7668
diff
changeset
|
229 |
* @exception IllegalArgumentException if <code>columns</code> < 0 |
2 | 230 |
*/ |
231 |
public JTextField(Document doc, String text, int columns) { |
|
232 |
if (columns < 0) { |
|
233 |
throw new IllegalArgumentException("columns less than zero."); |
|
234 |
} |
|
235 |
visibility = new DefaultBoundedRangeModel(); |
|
236 |
visibility.addChangeListener(new ScrollRepainter()); |
|
237 |
this.columns = columns; |
|
238 |
if (doc == null) { |
|
239 |
doc = createDefaultModel(); |
|
240 |
} |
|
241 |
setDocument(doc); |
|
242 |
if (text != null) { |
|
243 |
setText(text); |
|
244 |
} |
|
245 |
} |
|
246 |
||
247 |
/** |
|
248 |
* Gets the class ID for a UI. |
|
249 |
* |
|
250 |
* @return the string "TextFieldUI" |
|
251 |
* @see JComponent#getUIClassID |
|
252 |
* @see UIDefaults#getUI |
|
253 |
*/ |
|
254 |
public String getUIClassID() { |
|
255 |
return uiClassID; |
|
256 |
} |
|
257 |
||
258 |
||
259 |
/** |
|
260 |
* Associates the editor with a text document. |
|
261 |
* The currently registered factory is used to build a view for |
|
262 |
* the document, which gets displayed by the editor after revalidation. |
|
263 |
* A PropertyChange event ("document") is propagated to each listener. |
|
264 |
* |
|
265 |
* @param doc the document to display/edit |
|
266 |
* @see #getDocument |
|
267 |
* @beaninfo |
|
268 |
* description: the text document model |
|
269 |
* bound: true |
|
270 |
* expert: true |
|
271 |
*/ |
|
272 |
public void setDocument(Document doc) { |
|
273 |
if (doc != null) { |
|
274 |
doc.putProperty("filterNewlines", Boolean.TRUE); |
|
275 |
} |
|
276 |
super.setDocument(doc); |
|
277 |
} |
|
278 |
||
279 |
/** |
|
280 |
* Calls to <code>revalidate</code> that come from within the |
|
281 |
* textfield itself will |
|
282 |
* be handled by validating the textfield, unless the textfield |
|
283 |
* is contained within a <code>JViewport</code>, |
|
284 |
* in which case this returns false. |
|
285 |
* |
|
286 |
* @return if the parent of this textfield is a <code>JViewPort</code> |
|
287 |
* return false, otherwise return true |
|
288 |
* |
|
289 |
* @see JComponent#revalidate |
|
290 |
* @see JComponent#isValidateRoot |
|
4261 | 291 |
* @see java.awt.Container#isValidateRoot |
2 | 292 |
*/ |
4261 | 293 |
@Override |
2 | 294 |
public boolean isValidateRoot() { |
5449 | 295 |
return !(SwingUtilities.getUnwrappedParent(this) instanceof JViewport); |
2 | 296 |
} |
297 |
||
298 |
||
299 |
/** |
|
300 |
* Returns the horizontal alignment of the text. |
|
301 |
* Valid keys are: |
|
302 |
* <ul> |
|
303 |
* <li><code>JTextField.LEFT</code> |
|
304 |
* <li><code>JTextField.CENTER</code> |
|
305 |
* <li><code>JTextField.RIGHT</code> |
|
306 |
* <li><code>JTextField.LEADING</code> |
|
307 |
* <li><code>JTextField.TRAILING</code> |
|
308 |
* </ul> |
|
309 |
* |
|
310 |
* @return the horizontal alignment |
|
311 |
*/ |
|
312 |
public int getHorizontalAlignment() { |
|
313 |
return horizontalAlignment; |
|
314 |
} |
|
315 |
||
316 |
/** |
|
317 |
* Sets the horizontal alignment of the text. |
|
318 |
* Valid keys are: |
|
319 |
* <ul> |
|
320 |
* <li><code>JTextField.LEFT</code> |
|
321 |
* <li><code>JTextField.CENTER</code> |
|
322 |
* <li><code>JTextField.RIGHT</code> |
|
323 |
* <li><code>JTextField.LEADING</code> |
|
324 |
* <li><code>JTextField.TRAILING</code> |
|
325 |
* </ul> |
|
326 |
* <code>invalidate</code> and <code>repaint</code> are called when the |
|
327 |
* alignment is set, |
|
328 |
* and a <code>PropertyChange</code> event ("horizontalAlignment") is fired. |
|
329 |
* |
|
330 |
* @param alignment the alignment |
|
331 |
* @exception IllegalArgumentException if <code>alignment</code> |
|
332 |
* is not a valid key |
|
333 |
* @beaninfo |
|
334 |
* preferred: true |
|
335 |
* bound: true |
|
336 |
* description: Set the field alignment to LEFT, CENTER, RIGHT, |
|
337 |
* LEADING (the default) or TRAILING |
|
338 |
* enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT |
|
339 |
* LEADING JTextField.LEADING TRAILING JTextField.TRAILING |
|
340 |
*/ |
|
341 |
public void setHorizontalAlignment(int alignment) { |
|
342 |
if (alignment == horizontalAlignment) return; |
|
343 |
int oldValue = horizontalAlignment; |
|
344 |
if ((alignment == LEFT) || (alignment == CENTER) || |
|
345 |
(alignment == RIGHT)|| (alignment == LEADING) || |
|
346 |
(alignment == TRAILING)) { |
|
347 |
horizontalAlignment = alignment; |
|
348 |
} else { |
|
349 |
throw new IllegalArgumentException("horizontalAlignment"); |
|
350 |
} |
|
351 |
firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment); |
|
352 |
invalidate(); |
|
353 |
repaint(); |
|
354 |
} |
|
355 |
||
356 |
/** |
|
357 |
* Creates the default implementation of the model |
|
358 |
* to be used at construction if one isn't explicitly |
|
359 |
* given. An instance of <code>PlainDocument</code> is returned. |
|
360 |
* |
|
361 |
* @return the default model implementation |
|
362 |
*/ |
|
363 |
protected Document createDefaultModel() { |
|
364 |
return new PlainDocument(); |
|
365 |
} |
|
366 |
||
367 |
/** |
|
368 |
* Returns the number of columns in this <code>TextField</code>. |
|
369 |
* |
|
370 |
* @return the number of columns >= 0 |
|
371 |
*/ |
|
372 |
public int getColumns() { |
|
373 |
return columns; |
|
374 |
} |
|
375 |
||
376 |
/** |
|
377 |
* Sets the number of columns in this <code>TextField</code>, |
|
378 |
* and then invalidate the layout. |
|
379 |
* |
|
380 |
* @param columns the number of columns >= 0 |
|
381 |
* @exception IllegalArgumentException if <code>columns</code> |
|
382 |
* is less than 0 |
|
383 |
* @beaninfo |
|
384 |
* description: the number of columns preferred for display |
|
385 |
*/ |
|
386 |
public void setColumns(int columns) { |
|
387 |
int oldVal = this.columns; |
|
388 |
if (columns < 0) { |
|
389 |
throw new IllegalArgumentException("columns less than zero."); |
|
390 |
} |
|
391 |
if (columns != oldVal) { |
|
392 |
this.columns = columns; |
|
393 |
invalidate(); |
|
394 |
} |
|
395 |
} |
|
396 |
||
397 |
/** |
|
398 |
* Returns the column width. |
|
399 |
* The meaning of what a column is can be considered a fairly weak |
|
400 |
* notion for some fonts. This method is used to define the width |
|
401 |
* of a column. By default this is defined to be the width of the |
|
402 |
* character <em>m</em> for the font used. This method can be |
|
403 |
* redefined to be some alternative amount |
|
404 |
* |
|
405 |
* @return the column width >= 1 |
|
406 |
*/ |
|
407 |
protected int getColumnWidth() { |
|
408 |
if (columnWidth == 0) { |
|
409 |
FontMetrics metrics = getFontMetrics(getFont()); |
|
410 |
columnWidth = metrics.charWidth('m'); |
|
411 |
} |
|
412 |
return columnWidth; |
|
413 |
} |
|
414 |
||
415 |
/** |
|
416 |
* Returns the preferred size <code>Dimensions</code> needed for this |
|
417 |
* <code>TextField</code>. If a non-zero number of columns has been |
|
418 |
* set, the width is set to the columns multiplied by |
|
419 |
* the column width. |
|
420 |
* |
|
421 |
* @return the dimension of this textfield |
|
422 |
*/ |
|
423 |
public Dimension getPreferredSize() { |
|
424 |
Dimension size = super.getPreferredSize(); |
|
425 |
if (columns != 0) { |
|
426 |
Insets insets = getInsets(); |
|
427 |
size.width = columns * getColumnWidth() + |
|
428 |
insets.left + insets.right; |
|
429 |
} |
|
430 |
return size; |
|
431 |
} |
|
432 |
||
433 |
/** |
|
434 |
* Sets the current font. This removes cached row height and column |
|
435 |
* width so the new font will be reflected. |
|
436 |
* <code>revalidate</code> is called after setting the font. |
|
437 |
* |
|
438 |
* @param f the new font |
|
439 |
*/ |
|
440 |
public void setFont(Font f) { |
|
441 |
super.setFont(f); |
|
442 |
columnWidth = 0; |
|
443 |
} |
|
444 |
||
445 |
/** |
|
446 |
* Adds the specified action listener to receive |
|
447 |
* action events from this textfield. |
|
448 |
* |
|
449 |
* @param l the action listener to be added |
|
450 |
*/ |
|
451 |
public synchronized void addActionListener(ActionListener l) { |
|
452 |
listenerList.add(ActionListener.class, l); |
|
453 |
} |
|
454 |
||
455 |
/** |
|
456 |
* Removes the specified action listener so that it no longer |
|
457 |
* receives action events from this textfield. |
|
458 |
* |
|
459 |
* @param l the action listener to be removed |
|
460 |
*/ |
|
461 |
public synchronized void removeActionListener(ActionListener l) { |
|
462 |
if ((l != null) && (getAction() == l)) { |
|
463 |
setAction(null); |
|
464 |
} else { |
|
465 |
listenerList.remove(ActionListener.class, l); |
|
466 |
} |
|
467 |
} |
|
468 |
||
469 |
/** |
|
470 |
* Returns an array of all the <code>ActionListener</code>s added |
|
471 |
* to this JTextField with addActionListener(). |
|
472 |
* |
|
473 |
* @return all of the <code>ActionListener</code>s added or an empty |
|
474 |
* array if no listeners have been added |
|
475 |
* @since 1.4 |
|
476 |
*/ |
|
477 |
public synchronized ActionListener[] getActionListeners() { |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
2
diff
changeset
|
478 |
return listenerList.getListeners(ActionListener.class); |
2 | 479 |
} |
480 |
||
481 |
/** |
|
482 |
* Notifies all listeners that have registered interest for |
|
483 |
* notification on this event type. The event instance |
|
484 |
* is lazily created. |
|
485 |
* The listener list is processed in last to |
|
486 |
* first order. |
|
487 |
* @see EventListenerList |
|
488 |
*/ |
|
489 |
protected void fireActionPerformed() { |
|
490 |
// Guaranteed to return a non-null array |
|
491 |
Object[] listeners = listenerList.getListenerList(); |
|
492 |
int modifiers = 0; |
|
493 |
AWTEvent currentEvent = EventQueue.getCurrentEvent(); |
|
494 |
if (currentEvent instanceof InputEvent) { |
|
495 |
modifiers = ((InputEvent)currentEvent).getModifiers(); |
|
496 |
} else if (currentEvent instanceof ActionEvent) { |
|
497 |
modifiers = ((ActionEvent)currentEvent).getModifiers(); |
|
498 |
} |
|
499 |
ActionEvent e = |
|
500 |
new ActionEvent(this, ActionEvent.ACTION_PERFORMED, |
|
501 |
(command != null) ? command : getText(), |
|
502 |
EventQueue.getMostRecentEventTime(), modifiers); |
|
503 |
||
504 |
// Process the listeners last to first, notifying |
|
505 |
// those that are interested in this event |
|
506 |
for (int i = listeners.length-2; i>=0; i-=2) { |
|
507 |
if (listeners[i]==ActionListener.class) { |
|
508 |
((ActionListener)listeners[i+1]).actionPerformed(e); |
|
509 |
} |
|
510 |
} |
|
511 |
} |
|
512 |
||
513 |
/** |
|
514 |
* Sets the command string used for action events. |
|
515 |
* |
|
516 |
* @param command the command string |
|
517 |
*/ |
|
518 |
public void setActionCommand(String command) { |
|
519 |
this.command = command; |
|
520 |
} |
|
521 |
||
522 |
private Action action; |
|
523 |
private PropertyChangeListener actionPropertyChangeListener; |
|
524 |
||
525 |
/** |
|
526 |
* Sets the <code>Action</code> for the <code>ActionEvent</code> source. |
|
527 |
* The new <code>Action</code> replaces |
|
528 |
* any previously set <code>Action</code> but does not affect |
|
529 |
* <code>ActionListeners</code> independently |
|
530 |
* added with <code>addActionListener</code>. |
|
531 |
* If the <code>Action</code> is already a registered |
|
532 |
* <code>ActionListener</code> |
|
533 |
* for the <code>ActionEvent</code> source, it is not re-registered. |
|
534 |
* <p> |
|
535 |
* Setting the <code>Action</code> results in immediately changing |
|
536 |
* all the properties described in <a href="Action.html#buttonActions"> |
|
537 |
* Swing Components Supporting <code>Action</code></a>. |
|
538 |
* Subsequently, the textfield's properties are automatically updated |
|
539 |
* as the <code>Action</code>'s properties change. |
|
540 |
* <p> |
|
541 |
* This method uses three other methods to set |
|
542 |
* and help track the <code>Action</code>'s property values. |
|
543 |
* It uses the <code>configurePropertiesFromAction</code> method |
|
544 |
* to immediately change the textfield's properties. |
|
545 |
* To track changes in the <code>Action</code>'s property values, |
|
546 |
* this method registers the <code>PropertyChangeListener</code> |
|
547 |
* returned by <code>createActionPropertyChangeListener</code>. The |
|
548 |
* default {@code PropertyChangeListener} invokes the |
|
549 |
* {@code actionPropertyChanged} method when a property in the |
|
550 |
* {@code Action} changes. |
|
551 |
* |
|
552 |
* @param a the <code>Action</code> for the <code>JTextField</code>, |
|
553 |
* or <code>null</code> |
|
554 |
* @since 1.3 |
|
555 |
* @see Action |
|
556 |
* @see #getAction |
|
557 |
* @see #configurePropertiesFromAction |
|
558 |
* @see #createActionPropertyChangeListener |
|
559 |
* @see #actionPropertyChanged |
|
560 |
* @beaninfo |
|
561 |
* bound: true |
|
562 |
* attribute: visualUpdate true |
|
563 |
* description: the Action instance connected with this ActionEvent source |
|
564 |
*/ |
|
565 |
public void setAction(Action a) { |
|
566 |
Action oldValue = getAction(); |
|
567 |
if (action==null || !action.equals(a)) { |
|
568 |
action = a; |
|
569 |
if (oldValue!=null) { |
|
570 |
removeActionListener(oldValue); |
|
571 |
oldValue.removePropertyChangeListener(actionPropertyChangeListener); |
|
572 |
actionPropertyChangeListener = null; |
|
573 |
} |
|
574 |
configurePropertiesFromAction(action); |
|
575 |
if (action!=null) { |
|
576 |
// Don't add if it is already a listener |
|
577 |
if (!isListener(ActionListener.class, action)) { |
|
578 |
addActionListener(action); |
|
579 |
} |
|
580 |
// Reverse linkage: |
|
581 |
actionPropertyChangeListener = createActionPropertyChangeListener(action); |
|
582 |
action.addPropertyChangeListener(actionPropertyChangeListener); |
|
583 |
} |
|
584 |
firePropertyChange("action", oldValue, action); |
|
585 |
} |
|
586 |
} |
|
587 |
||
588 |
private boolean isListener(Class c, ActionListener a) { |
|
589 |
boolean isListener = false; |
|
590 |
Object[] listeners = listenerList.getListenerList(); |
|
591 |
for (int i = listeners.length-2; i>=0; i-=2) { |
|
592 |
if (listeners[i]==c && listeners[i+1]==a) { |
|
593 |
isListener=true; |
|
594 |
} |
|
595 |
} |
|
596 |
return isListener; |
|
597 |
} |
|
598 |
||
599 |
/** |
|
600 |
* Returns the currently set <code>Action</code> for this |
|
601 |
* <code>ActionEvent</code> source, or <code>null</code> |
|
602 |
* if no <code>Action</code> is set. |
|
603 |
* |
|
604 |
* @return the <code>Action</code> for this <code>ActionEvent</code> source, |
|
605 |
* or <code>null</code> |
|
606 |
* @since 1.3 |
|
607 |
* @see Action |
|
608 |
* @see #setAction |
|
609 |
*/ |
|
610 |
public Action getAction() { |
|
611 |
return action; |
|
612 |
} |
|
613 |
||
614 |
/** |
|
615 |
* Sets the properties on this textfield to match those in the specified |
|
616 |
* <code>Action</code>. Refer to <a href="Action.html#buttonActions"> |
|
617 |
* Swing Components Supporting <code>Action</code></a> for more |
|
618 |
* details as to which properties this sets. |
|
619 |
* |
|
620 |
* @param a the <code>Action</code> from which to get the properties, |
|
621 |
* or <code>null</code> |
|
622 |
* @since 1.3 |
|
623 |
* @see Action |
|
624 |
* @see #setAction |
|
625 |
*/ |
|
626 |
protected void configurePropertiesFromAction(Action a) { |
|
627 |
AbstractAction.setEnabledFromAction(this, a); |
|
628 |
AbstractAction.setToolTipTextFromAction(this, a); |
|
629 |
setActionCommandFromAction(a); |
|
630 |
} |
|
631 |
||
632 |
/** |
|
633 |
* Updates the textfield's state in response to property changes in |
|
634 |
* associated action. This method is invoked from the |
|
635 |
* {@code PropertyChangeListener} returned from |
|
636 |
* {@code createActionPropertyChangeListener}. Subclasses do not normally |
|
637 |
* need to invoke this. Subclasses that support additional {@code Action} |
|
638 |
* properties should override this and |
|
639 |
* {@code configurePropertiesFromAction}. |
|
640 |
* <p> |
|
641 |
* Refer to the table at <a href="Action.html#buttonActions"> |
|
642 |
* Swing Components Supporting <code>Action</code></a> for a list of |
|
643 |
* the properties this method sets. |
|
644 |
* |
|
645 |
* @param action the <code>Action</code> associated with this textfield |
|
646 |
* @param propertyName the name of the property that changed |
|
647 |
* @since 1.6 |
|
648 |
* @see Action |
|
649 |
* @see #configurePropertiesFromAction |
|
650 |
*/ |
|
651 |
protected void actionPropertyChanged(Action action, String propertyName) { |
|
652 |
if (propertyName == Action.ACTION_COMMAND_KEY) { |
|
653 |
setActionCommandFromAction(action); |
|
654 |
} else if (propertyName == "enabled") { |
|
655 |
AbstractAction.setEnabledFromAction(this, action); |
|
656 |
} else if (propertyName == Action.SHORT_DESCRIPTION) { |
|
657 |
AbstractAction.setToolTipTextFromAction(this, action); |
|
658 |
} |
|
659 |
} |
|
660 |
||
661 |
private void setActionCommandFromAction(Action action) { |
|
662 |
setActionCommand((action == null) ? null : |
|
663 |
(String)action.getValue(Action.ACTION_COMMAND_KEY)); |
|
664 |
} |
|
665 |
||
666 |
/** |
|
667 |
* Creates and returns a <code>PropertyChangeListener</code> that is |
|
668 |
* responsible for listening for changes from the specified |
|
669 |
* <code>Action</code> and updating the appropriate properties. |
|
670 |
* <p> |
|
671 |
* <b>Warning:</b> If you subclass this do not create an anonymous |
|
672 |
* inner class. If you do the lifetime of the textfield will be tied to |
|
673 |
* that of the <code>Action</code>. |
|
674 |
* |
|
675 |
* @param a the textfield's action |
|
676 |
* @since 1.3 |
|
677 |
* @see Action |
|
678 |
* @see #setAction |
|
679 |
*/ |
|
680 |
protected PropertyChangeListener createActionPropertyChangeListener(Action a) { |
|
681 |
return new TextFieldActionPropertyChangeListener(this, a); |
|
682 |
} |
|
683 |
||
684 |
private static class TextFieldActionPropertyChangeListener extends |
|
685 |
ActionPropertyChangeListener<JTextField> { |
|
686 |
TextFieldActionPropertyChangeListener(JTextField tf, Action a) { |
|
687 |
super(tf, a); |
|
688 |
} |
|
689 |
||
690 |
protected void actionPropertyChanged(JTextField textField, |
|
691 |
Action action, |
|
692 |
PropertyChangeEvent e) { |
|
693 |
if (AbstractAction.shouldReconfigure(e)) { |
|
694 |
textField.configurePropertiesFromAction(action); |
|
695 |
} else { |
|
696 |
textField.actionPropertyChanged(action, e.getPropertyName()); |
|
697 |
} |
|
698 |
} |
|
699 |
} |
|
700 |
||
701 |
/** |
|
702 |
* Fetches the command list for the editor. This is |
|
703 |
* the list of commands supported by the plugged-in UI |
|
704 |
* augmented by the collection of commands that the |
|
705 |
* editor itself supports. These are useful for binding |
|
706 |
* to events, such as in a keymap. |
|
707 |
* |
|
708 |
* @return the command list |
|
709 |
*/ |
|
710 |
public Action[] getActions() { |
|
711 |
return TextAction.augmentList(super.getActions(), defaultActions); |
|
712 |
} |
|
713 |
||
714 |
/** |
|
715 |
* Processes action events occurring on this textfield by |
|
716 |
* dispatching them to any registered <code>ActionListener</code> objects. |
|
717 |
* This is normally called by the controller registered with |
|
718 |
* textfield. |
|
719 |
*/ |
|
720 |
public void postActionEvent() { |
|
721 |
fireActionPerformed(); |
|
722 |
} |
|
723 |
||
724 |
// --- Scrolling support ----------------------------------- |
|
725 |
||
726 |
/** |
|
727 |
* Gets the visibility of the text field. This can |
|
728 |
* be adjusted to change the location of the visible |
|
729 |
* area if the size of the field is greater than |
|
730 |
* the area that was allocated to the field. |
|
731 |
* |
|
732 |
* <p> |
|
733 |
* The fields look-and-feel implementation manages |
|
734 |
* the values of the minimum, maximum, and extent |
|
735 |
* properties on the <code>BoundedRangeModel</code>. |
|
736 |
* |
|
737 |
* @return the visibility |
|
738 |
* @see BoundedRangeModel |
|
739 |
*/ |
|
740 |
public BoundedRangeModel getHorizontalVisibility() { |
|
741 |
return visibility; |
|
742 |
} |
|
743 |
||
744 |
/** |
|
745 |
* Gets the scroll offset, in pixels. |
|
746 |
* |
|
747 |
* @return the offset >= 0 |
|
748 |
*/ |
|
749 |
public int getScrollOffset() { |
|
750 |
return visibility.getValue(); |
|
751 |
} |
|
752 |
||
753 |
/** |
|
754 |
* Sets the scroll offset, in pixels. |
|
755 |
* |
|
756 |
* @param scrollOffset the offset >= 0 |
|
757 |
*/ |
|
758 |
public void setScrollOffset(int scrollOffset) { |
|
759 |
visibility.setValue(scrollOffset); |
|
760 |
} |
|
761 |
||
762 |
/** |
|
763 |
* Scrolls the field left or right. |
|
764 |
* |
|
765 |
* @param r the region to scroll |
|
766 |
*/ |
|
767 |
public void scrollRectToVisible(Rectangle r) { |
|
768 |
// convert to coordinate system of the bounded range |
|
769 |
Insets i = getInsets(); |
|
770 |
int x0 = r.x + visibility.getValue() - i.left; |
|
771 |
int x1 = x0 + r.width; |
|
772 |
if (x0 < visibility.getValue()) { |
|
773 |
// Scroll to the left |
|
774 |
visibility.setValue(x0); |
|
775 |
} else if(x1 > visibility.getValue() + visibility.getExtent()) { |
|
776 |
// Scroll to the right |
|
777 |
visibility.setValue(x1 - visibility.getExtent()); |
|
778 |
} |
|
779 |
} |
|
780 |
||
781 |
/** |
|
782 |
* Returns true if the receiver has an <code>ActionListener</code> |
|
783 |
* installed. |
|
784 |
*/ |
|
785 |
boolean hasActionListener() { |
|
786 |
// Guaranteed to return a non-null array |
|
787 |
Object[] listeners = listenerList.getListenerList(); |
|
788 |
// Process the listeners last to first, notifying |
|
789 |
// those that are interested in this event |
|
790 |
for (int i = listeners.length-2; i>=0; i-=2) { |
|
791 |
if (listeners[i]==ActionListener.class) { |
|
792 |
return true; |
|
793 |
} |
|
794 |
} |
|
795 |
return false; |
|
796 |
} |
|
797 |
||
798 |
// --- variables ------------------------------------------- |
|
799 |
||
800 |
/** |
|
801 |
* Name of the action to send notification that the |
|
802 |
* contents of the field have been accepted. Typically |
|
803 |
* this is bound to a carriage-return. |
|
804 |
*/ |
|
805 |
public static final String notifyAction = "notify-field-accept"; |
|
806 |
||
807 |
private BoundedRangeModel visibility; |
|
808 |
private int horizontalAlignment = LEADING; |
|
809 |
private int columns; |
|
810 |
private int columnWidth; |
|
811 |
private String command; |
|
812 |
||
813 |
private static final Action[] defaultActions = { |
|
814 |
new NotifyAction() |
|
815 |
}; |
|
816 |
||
817 |
/** |
|
818 |
* @see #getUIClassID |
|
819 |
* @see #readObject |
|
820 |
*/ |
|
821 |
private static final String uiClassID = "TextFieldUI"; |
|
822 |
||
823 |
// --- Action implementations ----------------------------------- |
|
824 |
||
825 |
// Note that JFormattedTextField.CommitAction extends this |
|
826 |
static class NotifyAction extends TextAction { |
|
827 |
||
828 |
NotifyAction() { |
|
829 |
super(notifyAction); |
|
830 |
} |
|
831 |
||
832 |
public void actionPerformed(ActionEvent e) { |
|
833 |
JTextComponent target = getFocusedComponent(); |
|
834 |
if (target instanceof JTextField) { |
|
835 |
JTextField field = (JTextField) target; |
|
836 |
field.postActionEvent(); |
|
837 |
} |
|
838 |
} |
|
839 |
||
840 |
public boolean isEnabled() { |
|
841 |
JTextComponent target = getFocusedComponent(); |
|
842 |
if (target instanceof JTextField) { |
|
843 |
return ((JTextField)target).hasActionListener(); |
|
844 |
} |
|
845 |
return false; |
|
846 |
} |
|
847 |
} |
|
848 |
||
849 |
class ScrollRepainter implements ChangeListener, Serializable { |
|
850 |
||
851 |
public void stateChanged(ChangeEvent e) { |
|
852 |
repaint(); |
|
853 |
} |
|
854 |
||
855 |
} |
|
856 |
||
857 |
||
858 |
/** |
|
859 |
* See <code>readObject</code> and <code>writeObject</code> in |
|
860 |
* <code>JComponent</code> for more |
|
861 |
* information about serialization in Swing. |
|
862 |
*/ |
|
863 |
private void writeObject(ObjectOutputStream s) throws IOException { |
|
864 |
s.defaultWriteObject(); |
|
865 |
if (getUIClassID().equals(uiClassID)) { |
|
866 |
byte count = JComponent.getWriteObjCounter(this); |
|
867 |
JComponent.setWriteObjCounter(this, --count); |
|
868 |
if (count == 0 && ui != null) { |
|
869 |
ui.installUI(this); |
|
870 |
} |
|
871 |
} |
|
872 |
} |
|
873 |
||
874 |
||
875 |
/** |
|
876 |
* Returns a string representation of this <code>JTextField</code>. |
|
877 |
* This method is intended to be used only for debugging purposes, |
|
878 |
* and the content and format of the returned string may vary between |
|
879 |
* implementations. The returned string may be empty but may not |
|
880 |
* be <code>null</code>. |
|
881 |
* |
|
882 |
* @return a string representation of this <code>JTextField</code> |
|
883 |
*/ |
|
884 |
protected String paramString() { |
|
885 |
String horizontalAlignmentString; |
|
886 |
if (horizontalAlignment == LEFT) { |
|
887 |
horizontalAlignmentString = "LEFT"; |
|
888 |
} else if (horizontalAlignment == CENTER) { |
|
889 |
horizontalAlignmentString = "CENTER"; |
|
890 |
} else if (horizontalAlignment == RIGHT) { |
|
891 |
horizontalAlignmentString = "RIGHT"; |
|
892 |
} else if (horizontalAlignment == LEADING) { |
|
893 |
horizontalAlignmentString = "LEADING"; |
|
894 |
} else if (horizontalAlignment == TRAILING) { |
|
895 |
horizontalAlignmentString = "TRAILING"; |
|
896 |
} else horizontalAlignmentString = ""; |
|
897 |
String commandString = (command != null ? |
|
898 |
command : ""); |
|
899 |
||
900 |
return super.paramString() + |
|
901 |
",columns=" + columns + |
|
902 |
",columnWidth=" + columnWidth + |
|
903 |
",command=" + commandString + |
|
904 |
",horizontalAlignment=" + horizontalAlignmentString; |
|
905 |
} |
|
906 |
||
907 |
||
908 |
///////////////// |
|
909 |
// Accessibility support |
|
910 |
//////////////// |
|
911 |
||
912 |
||
913 |
/** |
|
914 |
* Gets the <code>AccessibleContext</code> associated with this |
|
915 |
* <code>JTextField</code>. For <code>JTextFields</code>, |
|
916 |
* the <code>AccessibleContext</code> takes the form of an |
|
917 |
* <code>AccessibleJTextField</code>. |
|
918 |
* A new <code>AccessibleJTextField</code> instance is created |
|
919 |
* if necessary. |
|
920 |
* |
|
921 |
* @return an <code>AccessibleJTextField</code> that serves as the |
|
922 |
* <code>AccessibleContext</code> of this <code>JTextField</code> |
|
923 |
*/ |
|
924 |
public AccessibleContext getAccessibleContext() { |
|
925 |
if (accessibleContext == null) { |
|
926 |
accessibleContext = new AccessibleJTextField(); |
|
927 |
} |
|
928 |
return accessibleContext; |
|
929 |
} |
|
930 |
||
931 |
/** |
|
932 |
* This class implements accessibility support for the |
|
933 |
* <code>JTextField</code> class. It provides an implementation of the |
|
934 |
* Java Accessibility API appropriate to text field user-interface |
|
935 |
* elements. |
|
936 |
* <p> |
|
937 |
* <strong>Warning:</strong> |
|
938 |
* Serialized objects of this class will not be compatible with |
|
939 |
* future Swing releases. The current serialization support is |
|
940 |
* appropriate for short term storage or RMI between applications running |
|
941 |
* the same version of Swing. As of 1.4, support for long term storage |
|
20458 | 942 |
* of all JavaBeans™ |
2 | 943 |
* has been added to the <code>java.beans</code> package. |
944 |
* Please see {@link java.beans.XMLEncoder}. |
|
945 |
*/ |
|
946 |
protected class AccessibleJTextField extends AccessibleJTextComponent { |
|
947 |
||
948 |
/** |
|
949 |
* Gets the state set of this object. |
|
950 |
* |
|
951 |
* @return an instance of AccessibleStateSet describing the states |
|
952 |
* of the object |
|
953 |
* @see AccessibleState |
|
954 |
*/ |
|
955 |
public AccessibleStateSet getAccessibleStateSet() { |
|
956 |
AccessibleStateSet states = super.getAccessibleStateSet(); |
|
957 |
states.add(AccessibleState.SINGLE_LINE); |
|
958 |
return states; |
|
959 |
} |
|
960 |
} |
|
961 |
} |