History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/JTextField.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/JTextField.java+961−0
@@ -0,0 +1,961 @@
1+/*
2+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 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.
24+ */
25+package javax.swing;
26+
27+import sun.swing.SwingUtilities2;
28+
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
47+ * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a>
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+ * &nbsp; DocumentListener myListener = ??;
82+ * &nbsp; JTextField myArea = ??;
83+ * &nbsp; 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+&nbsp;public class UpperCaseField extends JTextField {
113+&nbsp;
114+&nbsp; public UpperCaseField(int cols) {
115+&nbsp; super(cols);
116+&nbsp; }
117+&nbsp;
118+&nbsp; protected Document createDefaultModel() {
119+&nbsp; return new UpperCaseDocument();
120+&nbsp; }
121+&nbsp;
122+&nbsp; static class UpperCaseDocument extends PlainDocument {
123+&nbsp;
124+&nbsp; public void insertString(int offs, String str, AttributeSet a)
125+&nbsp; throws BadLocationException {
126+&nbsp;
127+&nbsp; if (str == null) {
128+&nbsp; return;
129+&nbsp; }
130+&nbsp; char[] upper = str.toCharArray();
131+&nbsp; for (int i = 0; i < upper.length; i++) {
132+&nbsp; upper[i] = Character.toUpperCase(upper[i]);
133+&nbsp; }
134+&nbsp; super.insertString(offs, new String(upper), a);
135+&nbsp; }
136+&nbsp; }
137+&nbsp;}
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
151+ * of all JavaBeans<sup><font size="-2">TM</font></sup>
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
226+ * the preferred width >= 0; if <code>columns</code>
227+ * is set to zero, the preferred width will be whatever
228+ * naturally results from the component implementation
229+ * @exception IllegalArgumentException if <code>columns</code> < 0
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
291+ * @see java.awt.Container#isValidateRoot
292+ */
293+ @Override
294+ public boolean isValidateRoot() {
295+ return !(SwingUtilities.getUnwrappedParent(this) instanceof JViewport);
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 listenerList.getListeners(ActionListener.class);
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
942+ * of all JavaBeans<sup><font size="-2">TM</font></sup>
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+}