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