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