blob: b6d3b47f2851e35329985e86e94ec08229b420c0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
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
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
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 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing;
26
27import java.awt.*;
28import java.awt.event.*;
29import java.beans.*;
30import javax.swing.text.*;
31import javax.swing.plaf.*;
32import javax.swing.event.*;
33import javax.accessibility.*;
34
35import java.io.ObjectOutputStream;
36import java.io.ObjectInputStream;
37import java.io.IOException;
38import java.io.Serializable;
39
40/**
41 * <code>JTextField</code> is a lightweight component that allows the editing
42 * of a single line of text.
43 * For information on and examples of using text fields,
44 * see
45 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a>
46 * in <em>The Java Tutorial.</em>
47 *
48 * <p>
49 * <code>JTextField</code> is intended to be source-compatible
50 * with <code>java.awt.TextField</code> where it is reasonable to do so. This
51 * component has capabilities not found in the <code>java.awt.TextField</code>
52 * class. The superclass should be consulted for additional capabilities.
53 * <p>
54 * <code>JTextField</code> has a method to establish the string used as the
55 * command string for the action event that gets fired. The
56 * <code>java.awt.TextField</code> used the text of the field as the command
57 * string for the <code>ActionEvent</code>.
58 * <code>JTextField</code> will use the command
59 * string set with the <code>setActionCommand</code> method if not <code>null</code>,
60 * otherwise it will use the text of the field as a compatibility with
61 * <code>java.awt.TextField</code>.
62 * <p>
63 * The method <code>setEchoChar</code> and <code>getEchoChar</code>
64 * are not provided directly to avoid a new implementation of a
65 * pluggable look-and-feel inadvertently exposing password characters.
66 * To provide password-like services a separate class <code>JPasswordField</code>
67 * extends <code>JTextField</code> to provide this service with an independently
68 * pluggable look-and-feel.
69 * <p>
70 * The <code>java.awt.TextField</code> could be monitored for changes by adding
71 * a <code>TextListener</code> for <code>TextEvent</code>'s.
72 * In the <code>JTextComponent</code> based
73 * components, changes are broadcasted from the model via a
74 * <code>DocumentEvent</code> to <code>DocumentListeners</code>.
75 * The <code>DocumentEvent</code> gives
76 * the location of the change and the kind of change if desired.
77 * The code fragment might look something like:
78 * <pre><code>
79 * &nbsp; DocumentListener myListener = ??;
80 * &nbsp; JTextField myArea = ??;
81 * &nbsp; myArea.getDocument().addDocumentListener(myListener);
82 * </code></pre>
83 * <p>
84 * The horizontal alignment of <code>JTextField</code> can be set to be left
85 * justified, leading justified, centered, right justified or trailing justified.
86 * Right/trailing justification is useful if the required size
87 * of the field text is smaller than the size allocated to it.
88 * This is determined by the <code>setHorizontalAlignment</code>
89 * and <code>getHorizontalAlignment</code> methods. The default
90 * is to be leading justified.
91 * <p>
92 * How the text field consumes VK_ENTER events depends
93 * on whether the text field has any action listeners.
94 * If so, then VK_ENTER results in the listeners
95 * getting an ActionEvent,
96 * and the VK_ENTER event is consumed.
97 * This is compatible with how AWT text fields handle VK_ENTER events.
98 * If the text field has no action listeners, then as of v 1.3 the VK_ENTER
99 * event is not consumed. Instead, the bindings of ancestor components
100 * are processed, which enables the default button feature of
101 * JFC/Swing to work.
102 * <p>
103 * Customized fields can easily be created by extending the model and
104 * changing the default model provided. For example, the following piece
105 * of code will create a field that holds only upper case characters. It
106 * will work even if text is pasted into from the clipboard or it is altered via
107 * programmatic changes.
108 * <pre><code>
109
110&nbsp;public class UpperCaseField extends JTextField {
111&nbsp;
112&nbsp; public UpperCaseField(int cols) {
113&nbsp; super(cols);
114&nbsp; }
115&nbsp;
116&nbsp; protected Document createDefaultModel() {
117&nbsp; return new UpperCaseDocument();
118&nbsp; }
119&nbsp;
120&nbsp; static class UpperCaseDocument extends PlainDocument {
121&nbsp;
122&nbsp; public void insertString(int offs, String str, AttributeSet a)
123&nbsp; throws BadLocationException {
124&nbsp;
125&nbsp; if (str == null) {
126&nbsp; return;
127&nbsp; }
128&nbsp; char[] upper = str.toCharArray();
129&nbsp; for (int i = 0; i < upper.length; i++) {
130&nbsp; upper[i] = Character.toUpperCase(upper[i]);
131&nbsp; }
132&nbsp; super.insertString(offs, new String(upper), a);
133&nbsp; }
134&nbsp; }
135&nbsp;}
136
137 * </code></pre>
138 * <p>
139 * <strong>Warning:</strong> Swing is not thread safe. For more
140 * information see <a
141 * href="package-summary.html#threading">Swing's Threading
142 * Policy</a>.
143 * <p>
144 * <strong>Warning:</strong>
145 * Serialized objects of this class will not be compatible with
146 * future Swing releases. The current serialization support is
147 * appropriate for short term storage or RMI between applications running
148 * the same version of Swing. As of 1.4, support for long term storage
149 * of all JavaBeans<sup><font size="-2">TM</font></sup>
150 * has been added to the <code>java.beans</code> package.
151 * Please see {@link java.beans.XMLEncoder}.
152 *
153 * @beaninfo
154 * attribute: isContainer false
155 * description: A component which allows for the editing of a single line of text.
156 *
157 * @author Timothy Prinzing
158 * @see #setActionCommand
159 * @see JPasswordField
160 * @see #addActionListener
161 */
162public class JTextField extends JTextComponent implements SwingConstants {
163
164 /**
165 * Constructs a new <code>TextField</code>. A default model is created,
166 * the initial string is <code>null</code>,
167 * and the number of columns is set to 0.
168 */
169 public JTextField() {
170 this(null, null, 0);
171 }
172
173 /**
174 * Constructs a new <code>TextField</code> initialized with the
175 * specified text. A default model is created and the number of
176 * columns is 0.
177 *
178 * @param text the text to be displayed, or <code>null</code>
179 */
180 public JTextField(String text) {
181 this(null, text, 0);
182 }
183
184 /**
185 * Constructs a new empty <code>TextField</code> with the specified
186 * number of columns.
187 * A default model is created and the initial string is set to
188 * <code>null</code>.
189 *
190 * @param columns the number of columns to use to calculate
191 * the preferred width; if columns is set to zero, the
192 * preferred width will be whatever naturally results from
193 * the component implementation
194 */
195 public JTextField(int columns) {
196 this(null, null, columns);
197 }
198
199 /**
200 * Constructs a new <code>TextField</code> initialized with the
201 * specified text and columns. A default model is created.
202 *
203 * @param text the text to be displayed, or <code>null</code>
204 * @param columns the number of columns to use to calculate
205 * the preferred width; if columns is set to zero, the
206 * preferred width will be whatever naturally results from
207 * the component implementation
208 */
209 public JTextField(String text, int columns) {
210 this(null, text, columns);
211 }
212
213 /**
214 * Constructs a new <code>JTextField</code> that uses the given text
215 * storage model and the given number of columns.
216 * This is the constructor through which the other constructors feed.
217 * If the document is <code>null</code>, a default model is created.
218 *
219 * @param doc the text storage to use; if this is <code>null</code>,
220 * a default will be provided by calling the
221 * <code>createDefaultModel</code> method
222 * @param text the initial string to display, or <code>null</code>
223 * @param columns the number of columns to use to calculate
224 * the preferred width >= 0; if <code>columns</code>
225 * is set to zero, the preferred width will be whatever
226 * naturally results from the component implementation
227 * @exception IllegalArgumentException if <code>columns</code> < 0
228 */
229 public JTextField(Document doc, String text, int columns) {
230 if (columns < 0) {
231 throw new IllegalArgumentException("columns less than zero.");
232 }
233 visibility = new DefaultBoundedRangeModel();
234 visibility.addChangeListener(new ScrollRepainter());
235 this.columns = columns;
236 if (doc == null) {
237 doc = createDefaultModel();
238 }
239 setDocument(doc);
240 if (text != null) {
241 setText(text);
242 }
243 }
244
245 /**
246 * Gets the class ID for a UI.
247 *
248 * @return the string "TextFieldUI"
249 * @see JComponent#getUIClassID
250 * @see UIDefaults#getUI
251 */
252 public String getUIClassID() {
253 return uiClassID;
254 }
255
256
257 /**
258 * Associates the editor with a text document.
259 * The currently registered factory is used to build a view for
260 * the document, which gets displayed by the editor after revalidation.
261 * A PropertyChange event ("document") is propagated to each listener.
262 *
263 * @param doc the document to display/edit
264 * @see #getDocument
265 * @beaninfo
266 * description: the text document model
267 * bound: true
268 * expert: true
269 */
270 public void setDocument(Document doc) {
271 if (doc != null) {
272 doc.putProperty("filterNewlines", Boolean.TRUE);
273 }
274 super.setDocument(doc);
275 }
276
277 /**
278 * Calls to <code>revalidate</code> that come from within the
279 * textfield itself will
280 * be handled by validating the textfield, unless the textfield
281 * is contained within a <code>JViewport</code>,
282 * in which case this returns false.
283 *
284 * @return if the parent of this textfield is a <code>JViewPort</code>
285 * return false, otherwise return true
286 *
287 * @see JComponent#revalidate
288 * @see JComponent#isValidateRoot
289 */
290 public boolean isValidateRoot() {
291 Component parent = getParent();
292 if (parent instanceof JViewport) {
293 return false;
294 }
295 return true;
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() {
478 return (ActionListener[])listenerList.getListeners(
479 ActionListener.class);
480 }
481
482 /**
483 * Notifies all listeners that have registered interest for
484 * notification on this event type. The event instance
485 * is lazily created.
486 * The listener list is processed in last to
487 * first order.
488 * @see EventListenerList
489 */
490 protected void fireActionPerformed() {
491 // Guaranteed to return a non-null array
492 Object[] listeners = listenerList.getListenerList();
493 int modifiers = 0;
494 AWTEvent currentEvent = EventQueue.getCurrentEvent();
495 if (currentEvent instanceof InputEvent) {
496 modifiers = ((InputEvent)currentEvent).getModifiers();
497 } else if (currentEvent instanceof ActionEvent) {
498 modifiers = ((ActionEvent)currentEvent).getModifiers();
499 }
500 ActionEvent e =
501 new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
502 (command != null) ? command : getText(),
503 EventQueue.getMostRecentEventTime(), modifiers);
504
505 // Process the listeners last to first, notifying
506 // those that are interested in this event
507 for (int i = listeners.length-2; i>=0; i-=2) {
508 if (listeners[i]==ActionListener.class) {
509 ((ActionListener)listeners[i+1]).actionPerformed(e);
510 }
511 }
512 }
513
514 /**
515 * Sets the command string used for action events.
516 *
517 * @param command the command string
518 */
519 public void setActionCommand(String command) {
520 this.command = command;
521 }
522
523 private Action action;
524 private PropertyChangeListener actionPropertyChangeListener;
525
526 /**
527 * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
528 * The new <code>Action</code> replaces
529 * any previously set <code>Action</code> but does not affect
530 * <code>ActionListeners</code> independently
531 * added with <code>addActionListener</code>.
532 * If the <code>Action</code> is already a registered
533 * <code>ActionListener</code>
534 * for the <code>ActionEvent</code> source, it is not re-registered.
535 * <p>
536 * Setting the <code>Action</code> results in immediately changing
537 * all the properties described in <a href="Action.html#buttonActions">
538 * Swing Components Supporting <code>Action</code></a>.
539 * Subsequently, the textfield's properties are automatically updated
540 * as the <code>Action</code>'s properties change.
541 * <p>
542 * This method uses three other methods to set
543 * and help track the <code>Action</code>'s property values.
544 * It uses the <code>configurePropertiesFromAction</code> method
545 * to immediately change the textfield's properties.
546 * To track changes in the <code>Action</code>'s property values,
547 * this method registers the <code>PropertyChangeListener</code>
548 * returned by <code>createActionPropertyChangeListener</code>. The
549 * default {@code PropertyChangeListener} invokes the
550 * {@code actionPropertyChanged} method when a property in the
551 * {@code Action} changes.
552 *
553 * @param a the <code>Action</code> for the <code>JTextField</code>,
554 * or <code>null</code>
555 * @since 1.3
556 * @see Action
557 * @see #getAction
558 * @see #configurePropertiesFromAction
559 * @see #createActionPropertyChangeListener
560 * @see #actionPropertyChanged
561 * @beaninfo
562 * bound: true
563 * attribute: visualUpdate true
564 * description: the Action instance connected with this ActionEvent source
565 */
566 public void setAction(Action a) {
567 Action oldValue = getAction();
568 if (action==null || !action.equals(a)) {
569 action = a;
570 if (oldValue!=null) {
571 removeActionListener(oldValue);
572 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
573 actionPropertyChangeListener = null;
574 }
575 configurePropertiesFromAction(action);
576 if (action!=null) {
577 // Don't add if it is already a listener
578 if (!isListener(ActionListener.class, action)) {
579 addActionListener(action);
580 }
581 // Reverse linkage:
582 actionPropertyChangeListener = createActionPropertyChangeListener(action);
583 action.addPropertyChangeListener(actionPropertyChangeListener);
584 }
585 firePropertyChange("action", oldValue, action);
586 }
587 }
588
589 private boolean isListener(Class c, ActionListener a) {
590 boolean isListener = false;
591 Object[] listeners = listenerList.getListenerList();
592 for (int i = listeners.length-2; i>=0; i-=2) {
593 if (listeners[i]==c && listeners[i+1]==a) {
594 isListener=true;
595 }
596 }
597 return isListener;
598 }
599
600 /**
601 * Returns the currently set <code>Action</code> for this
602 * <code>ActionEvent</code> source, or <code>null</code>
603 * if no <code>Action</code> is set.
604 *
605 * @return the <code>Action</code> for this <code>ActionEvent</code> source,
606 * or <code>null</code>
607 * @since 1.3
608 * @see Action
609 * @see #setAction
610 */
611 public Action getAction() {
612 return action;
613 }
614
615 /**
616 * Sets the properties on this textfield to match those in the specified
617 * <code>Action</code>. Refer to <a href="Action.html#buttonActions">
618 * Swing Components Supporting <code>Action</code></a> for more
619 * details as to which properties this sets.
620 *
621 * @param a the <code>Action</code> from which to get the properties,
622 * or <code>null</code>
623 * @since 1.3
624 * @see Action
625 * @see #setAction
626 */
627 protected void configurePropertiesFromAction(Action a) {
628 AbstractAction.setEnabledFromAction(this, a);
629 AbstractAction.setToolTipTextFromAction(this, a);
630 setActionCommandFromAction(a);
631 }
632
633 /**
634 * Updates the textfield's state in response to property changes in
635 * associated action. This method is invoked from the
636 * {@code PropertyChangeListener} returned from
637 * {@code createActionPropertyChangeListener}. Subclasses do not normally
638 * need to invoke this. Subclasses that support additional {@code Action}
639 * properties should override this and
640 * {@code configurePropertiesFromAction}.
641 * <p>
642 * Refer to the table at <a href="Action.html#buttonActions">
643 * Swing Components Supporting <code>Action</code></a> for a list of
644 * the properties this method sets.
645 *
646 * @param action the <code>Action</code> associated with this textfield
647 * @param propertyName the name of the property that changed
648 * @since 1.6
649 * @see Action
650 * @see #configurePropertiesFromAction
651 */
652 protected void actionPropertyChanged(Action action, String propertyName) {
653 if (propertyName == Action.ACTION_COMMAND_KEY) {
654 setActionCommandFromAction(action);
655 } else if (propertyName == "enabled") {
656 AbstractAction.setEnabledFromAction(this, action);
657 } else if (propertyName == Action.SHORT_DESCRIPTION) {
658 AbstractAction.setToolTipTextFromAction(this, action);
659 }
660 }
661
662 private void setActionCommandFromAction(Action action) {
663 setActionCommand((action == null) ? null :
664 (String)action.getValue(Action.ACTION_COMMAND_KEY));
665 }
666
667 /**
668 * Creates and returns a <code>PropertyChangeListener</code> that is
669 * responsible for listening for changes from the specified
670 * <code>Action</code> and updating the appropriate properties.
671 * <p>
672 * <b>Warning:</b> If you subclass this do not create an anonymous
673 * inner class. If you do the lifetime of the textfield will be tied to
674 * that of the <code>Action</code>.
675 *
676 * @param a the textfield's action
677 * @since 1.3
678 * @see Action
679 * @see #setAction
680 */
681 protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
682 return new TextFieldActionPropertyChangeListener(this, a);
683 }
684
685 private static class TextFieldActionPropertyChangeListener extends
686 ActionPropertyChangeListener<JTextField> {
687 TextFieldActionPropertyChangeListener(JTextField tf, Action a) {
688 super(tf, a);
689 }
690
691 protected void actionPropertyChanged(JTextField textField,
692 Action action,
693 PropertyChangeEvent e) {
694 if (AbstractAction.shouldReconfigure(e)) {
695 textField.configurePropertiesFromAction(action);
696 } else {
697 textField.actionPropertyChanged(action, e.getPropertyName());
698 }
699 }
700 }
701
702 /**
703 * Fetches the command list for the editor. This is
704 * the list of commands supported by the plugged-in UI
705 * augmented by the collection of commands that the
706 * editor itself supports. These are useful for binding
707 * to events, such as in a keymap.
708 *
709 * @return the command list
710 */
711 public Action[] getActions() {
712 return TextAction.augmentList(super.getActions(), defaultActions);
713 }
714
715 /**
716 * Processes action events occurring on this textfield by
717 * dispatching them to any registered <code>ActionListener</code> objects.
718 * This is normally called by the controller registered with
719 * textfield.
720 */
721 public void postActionEvent() {
722 fireActionPerformed();
723 }
724
725 // --- Scrolling support -----------------------------------
726
727 /**
728 * Gets the visibility of the text field. This can
729 * be adjusted to change the location of the visible
730 * area if the size of the field is greater than
731 * the area that was allocated to the field.
732 *
733 * <p>
734 * The fields look-and-feel implementation manages
735 * the values of the minimum, maximum, and extent
736 * properties on the <code>BoundedRangeModel</code>.
737 *
738 * @return the visibility
739 * @see BoundedRangeModel
740 */
741 public BoundedRangeModel getHorizontalVisibility() {
742 return visibility;
743 }
744
745 /**
746 * Gets the scroll offset, in pixels.
747 *
748 * @return the offset >= 0
749 */
750 public int getScrollOffset() {
751 return visibility.getValue();
752 }
753
754 /**
755 * Sets the scroll offset, in pixels.
756 *
757 * @param scrollOffset the offset >= 0
758 */
759 public void setScrollOffset(int scrollOffset) {
760 visibility.setValue(scrollOffset);
761 }
762
763 /**
764 * Scrolls the field left or right.
765 *
766 * @param r the region to scroll
767 */
768 public void scrollRectToVisible(Rectangle r) {
769 // convert to coordinate system of the bounded range
770 Insets i = getInsets();
771 int x0 = r.x + visibility.getValue() - i.left;
772 int x1 = x0 + r.width;
773 if (x0 < visibility.getValue()) {
774 // Scroll to the left
775 visibility.setValue(x0);
776 } else if(x1 > visibility.getValue() + visibility.getExtent()) {
777 // Scroll to the right
778 visibility.setValue(x1 - visibility.getExtent());
779 }
780 }
781
782 /**
783 * Returns true if the receiver has an <code>ActionListener</code>
784 * installed.
785 */
786 boolean hasActionListener() {
787 // Guaranteed to return a non-null array
788 Object[] listeners = listenerList.getListenerList();
789 // Process the listeners last to first, notifying
790 // those that are interested in this event
791 for (int i = listeners.length-2; i>=0; i-=2) {
792 if (listeners[i]==ActionListener.class) {
793 return true;
794 }
795 }
796 return false;
797 }
798
799 // --- variables -------------------------------------------
800
801 /**
802 * Name of the action to send notification that the
803 * contents of the field have been accepted. Typically
804 * this is bound to a carriage-return.
805 */
806 public static final String notifyAction = "notify-field-accept";
807
808 private BoundedRangeModel visibility;
809 private int horizontalAlignment = LEADING;
810 private int columns;
811 private int columnWidth;
812 private String command;
813
814 private static final Action[] defaultActions = {
815 new NotifyAction()
816 };
817
818 /**
819 * @see #getUIClassID
820 * @see #readObject
821 */
822 private static final String uiClassID = "TextFieldUI";
823
824 // --- Action implementations -----------------------------------
825
826 // Note that JFormattedTextField.CommitAction extends this
827 static class NotifyAction extends TextAction {
828
829 NotifyAction() {
830 super(notifyAction);
831 }
832
833 public void actionPerformed(ActionEvent e) {
834 JTextComponent target = getFocusedComponent();
835 if (target instanceof JTextField) {
836 JTextField field = (JTextField) target;
837 field.postActionEvent();
838 }
839 }
840
841 public boolean isEnabled() {
842 JTextComponent target = getFocusedComponent();
843 if (target instanceof JTextField) {
844 return ((JTextField)target).hasActionListener();
845 }
846 return false;
847 }
848 }
849
850 class ScrollRepainter implements ChangeListener, Serializable {
851
852 public void stateChanged(ChangeEvent e) {
853 repaint();
854 }
855
856 }
857
858
859 /**
860 * See <code>readObject</code> and <code>writeObject</code> in
861 * <code>JComponent</code> for more
862 * information about serialization in Swing.
863 */
864 private void writeObject(ObjectOutputStream s) throws IOException {
865 s.defaultWriteObject();
866 if (getUIClassID().equals(uiClassID)) {
867 byte count = JComponent.getWriteObjCounter(this);
868 JComponent.setWriteObjCounter(this, --count);
869 if (count == 0 && ui != null) {
870 ui.installUI(this);
871 }
872 }
873 }
874
875
876 /**
877 * Returns a string representation of this <code>JTextField</code>.
878 * This method is intended to be used only for debugging purposes,
879 * and the content and format of the returned string may vary between
880 * implementations. The returned string may be empty but may not
881 * be <code>null</code>.
882 *
883 * @return a string representation of this <code>JTextField</code>
884 */
885 protected String paramString() {
886 String horizontalAlignmentString;
887 if (horizontalAlignment == LEFT) {
888 horizontalAlignmentString = "LEFT";
889 } else if (horizontalAlignment == CENTER) {
890 horizontalAlignmentString = "CENTER";
891 } else if (horizontalAlignment == RIGHT) {
892 horizontalAlignmentString = "RIGHT";
893 } else if (horizontalAlignment == LEADING) {
894 horizontalAlignmentString = "LEADING";
895 } else if (horizontalAlignment == TRAILING) {
896 horizontalAlignmentString = "TRAILING";
897 } else horizontalAlignmentString = "";
898 String commandString = (command != null ?
899 command : "");
900
901 return super.paramString() +
902 ",columns=" + columns +
903 ",columnWidth=" + columnWidth +
904 ",command=" + commandString +
905 ",horizontalAlignment=" + horizontalAlignmentString;
906 }
907
908
909/////////////////
910// Accessibility support
911////////////////
912
913
914 /**
915 * Gets the <code>AccessibleContext</code> associated with this
916 * <code>JTextField</code>. For <code>JTextFields</code>,
917 * the <code>AccessibleContext</code> takes the form of an
918 * <code>AccessibleJTextField</code>.
919 * A new <code>AccessibleJTextField</code> instance is created
920 * if necessary.
921 *
922 * @return an <code>AccessibleJTextField</code> that serves as the
923 * <code>AccessibleContext</code> of this <code>JTextField</code>
924 */
925 public AccessibleContext getAccessibleContext() {
926 if (accessibleContext == null) {
927 accessibleContext = new AccessibleJTextField();
928 }
929 return accessibleContext;
930 }
931
932 /**
933 * This class implements accessibility support for the
934 * <code>JTextField</code> class. It provides an implementation of the
935 * Java Accessibility API appropriate to text field user-interface
936 * elements.
937 * <p>
938 * <strong>Warning:</strong>
939 * Serialized objects of this class will not be compatible with
940 * future Swing releases. The current serialization support is
941 * appropriate for short term storage or RMI between applications running
942 * the same version of Swing. As of 1.4, support for long term storage
943 * of all JavaBeans<sup><font size="-2">TM</font></sup>
944 * has been added to the <code>java.beans</code> package.
945 * Please see {@link java.beans.XMLEncoder}.
946 */
947 protected class AccessibleJTextField extends AccessibleJTextComponent {
948
949 /**
950 * Gets the state set of this object.
951 *
952 * @return an instance of AccessibleStateSet describing the states
953 * of the object
954 * @see AccessibleState
955 */
956 public AccessibleStateSet getAccessibleStateSet() {
957 AccessibleStateSet states = super.getAccessibleStateSet();
958 states.add(AccessibleState.SINGLE_LINE);
959 return states;
960 }
961 }
962}