Frames | No Frames |
1: /* JTextField.java -- 2: Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing; 40: 41: import java.awt.Dimension; 42: import java.awt.Font; 43: import java.awt.FontMetrics; 44: import java.awt.event.ActionEvent; 45: import java.awt.event.ActionListener; 46: import java.beans.PropertyChangeEvent; 47: import java.beans.PropertyChangeListener; 48: 49: import javax.accessibility.AccessibleContext; 50: import javax.accessibility.AccessibleStateSet; 51: import javax.swing.text.Document; 52: import javax.swing.text.JTextComponent; 53: import javax.swing.text.PlainDocument; 54: import javax.swing.text.TextAction; 55: 56: public class JTextField extends JTextComponent 57: implements SwingConstants 58: { 59: /** 60: * AccessibleJTextField 61: */ 62: protected class AccessibleJTextField extends AccessibleJTextComponent 63: { 64: private static final long serialVersionUID = 8255147276740453036L; 65: 66: /** 67: * Constructor AccessibleJTextField 68: */ 69: protected AccessibleJTextField() 70: { 71: super(); 72: } 73: 74: /** 75: * Returns the accessible state of this <code>AccessibleJTextField</code>. 76: * 77: * @return the accessible state of this <code>AccessibleJTextField</code> 78: */ 79: public AccessibleStateSet getAccessibleStateSet() 80: { 81: AccessibleStateSet state = super.getAccessibleStateSet(); 82: // TODO: Figure out what state must be added here to the super's state. 83: return state; 84: } 85: } 86: 87: private static final long serialVersionUID = 353853209832607592L; 88: 89: private static final Action[] actions; 90: 91: /** 92: * Name of the action that gets sent when the content of the text field 93: * gets accepted. 94: */ 95: public static final String notifyAction = "notify-field-accept"; 96: 97: static 98: { 99: actions = new Action[1]; 100: actions[0] = new TextAction(notifyAction) 101: { 102: public void actionPerformed(ActionEvent event) 103: { 104: JTextField textField = (JTextField) event.getSource(); 105: textField.fireActionPerformed(); 106: } 107: }; 108: } 109: 110: private int columns; 111: private int align; 112: private int scrollOffset; 113: 114: /** @since 1.3 */ 115: private Action action; 116: 117: /** @since 1.3 */ 118: private String actionCommand; 119: 120: private PropertyChangeListener actionPropertyChangeListener; 121: 122: /** 123: * The horizontal visibility of the textfield. 124: */ 125: private BoundedRangeModel horizontalVisibility; 126: 127: /** 128: * Creates a new instance of <code>JTextField</code>. 129: */ 130: public JTextField() 131: { 132: this(null, null, 0); 133: } 134: 135: /** 136: * Creates a new instance of <code>JTextField</code>. 137: * 138: * @param text the initial text 139: */ 140: public JTextField(String text) 141: { 142: this(null, text, 0); 143: } 144: 145: /** 146: * Creates a new instance of <code>JTextField</code>. 147: * 148: * @param columns the number of columns 149: * 150: * @exception IllegalArgumentException if columns %lt; 0 151: */ 152: public JTextField(int columns) 153: { 154: this(null, null, columns); 155: } 156: 157: /** 158: * Creates a new instance of <code>JTextField</code>. 159: * 160: * @param text the initial text 161: * @param columns the number of columns 162: * 163: * @exception IllegalArgumentException if columns %lt; 0 164: */ 165: public JTextField(String text, int columns) 166: { 167: this(null, text, columns); 168: } 169: 170: /** 171: * Creates a new instance of <code>JTextField</code>. 172: * 173: * @param doc the document to use 174: * @param text the initial text 175: * @param columns the number of columns 176: * 177: * @exception IllegalArgumentException if columns %lt; 0 178: */ 179: public JTextField(Document doc, String text, int columns) 180: { 181: if (columns < 0) 182: throw new IllegalArgumentException(); 183: 184: this.columns = columns; 185: 186: setDocument(doc == null ? createDefaultModel() : doc); 187: 188: if (text != null) 189: setText(text); 190: 191: // default value for alignment 192: align = LEADING; 193: 194: // Initialize the horizontal visibility model. 195: horizontalVisibility = new DefaultBoundedRangeModel(); 196: } 197: 198: /** 199: * Creates the default model for this text field. 200: * This implementation returns an instance of <code>PlainDocument</code>. 201: * 202: * @return a new instance of the default model 203: */ 204: protected Document createDefaultModel() 205: { 206: PlainDocument doc = new PlainDocument(); 207: doc.putProperty("filterNewlines", Boolean.TRUE); 208: return doc; 209: } 210: 211: /** 212: * Returns the class ID for the UI. 213: * 214: * @return "TextFieldUI"; 215: */ 216: public String getUIClassID() 217: { 218: return "TextFieldUI"; 219: } 220: 221: /** 222: * Adds a new listener object to this text field. 223: * 224: * @param listener the listener to add 225: */ 226: public void addActionListener(ActionListener listener) 227: { 228: listenerList.add(ActionListener.class, listener); 229: } 230: 231: /** 232: * Removes a listener object from this text field. 233: * 234: * @param listener the listener to remove 235: */ 236: public void removeActionListener(ActionListener listener) 237: { 238: listenerList.remove(ActionListener.class, listener); 239: } 240: 241: /** 242: * Returns all registered <code>ActionListener</code> objects. 243: * 244: * @return an array of listeners 245: * 246: * @since 1.4 247: */ 248: public ActionListener[] getActionListeners() 249: { 250: return (ActionListener[]) getListeners(ActionListener.class); 251: } 252: 253: /** 254: * Sends an action event to all registered 255: * <code>ActionListener</code> objects. 256: */ 257: protected void fireActionPerformed() 258: { 259: ActionEvent event = new ActionEvent(this, 0, notifyAction); 260: ActionListener[] listeners = getActionListeners(); 261: 262: for (int index = 0; index < listeners.length; ++index) 263: listeners[index].actionPerformed(event); 264: } 265: 266: /** 267: * Returns the number of columns of this text field. 268: * 269: * @return the number of columns 270: */ 271: public int getColumns() 272: { 273: return columns; 274: } 275: 276: /** 277: * Sets the number of columns and then invalidates the layout. 278: * @param columns the number of columns 279: * @throws IllegalArgumentException if columns < 0 280: */ 281: public void setColumns(int columns) 282: { 283: if (columns < 0) 284: throw new IllegalArgumentException(); 285: 286: this.columns = columns; 287: invalidate(); 288: //FIXME: do we need this repaint call? 289: repaint(); 290: } 291: 292: /** 293: * Returns the horizontal alignment, which is one of: JTextField.LEFT, 294: * JTextField.CENTER, JTextField.RIGHT, JTextField.LEADING, 295: * JTextField.TRAILING. 296: * @return the horizontal alignment 297: */ 298: public int getHorizontalAlignment() 299: { 300: return align; 301: } 302: 303: /** 304: * Sets the horizontal alignment of the text. Calls invalidate and repaint 305: * and fires a property change event. 306: * @param newAlign must be one of: JTextField.LEFT, JTextField.CENTER, 307: * JTextField.RIGHT, JTextField.LEADING, JTextField.TRAILING. 308: * @throws IllegalArgumentException if newAlign is not one of the above. 309: */ 310: public void setHorizontalAlignment(int newAlign) 311: { 312: //FIXME: should throw an IllegalArgumentException if newAlign is invalid 313: if (align == newAlign) 314: return; 315: 316: int oldAlign = align; 317: align = newAlign; 318: firePropertyChange("horizontalAlignment", oldAlign, newAlign); 319: invalidate(); 320: repaint(); 321: } 322: 323: /** 324: * Sets the current font and revalidates so the font will take effect. 325: */ 326: public void setFont(Font newFont) 327: { 328: super.setFont(newFont); 329: revalidate(); 330: } 331: 332: /** 333: * Returns the preferred size. If there is a non-zero number of columns, 334: * this is the number of columns multiplied by the column width, otherwise 335: * it returns super.getPreferredSize(). 336: */ 337: public Dimension getPreferredSize() 338: { 339: Dimension size = super.getPreferredSize(); 340: 341: if (columns != 0) 342: size.width = columns * getColumnWidth(); 343: 344: return size; 345: } 346: 347: /** 348: * Returns the scroll offset in pixels. 349: * 350: * @return the scroll offset 351: */ 352: public int getScrollOffset() 353: { 354: //FIXME: this should return horizontalVisibility's value 355: return scrollOffset; 356: } 357: 358: /** 359: * Sets the scroll offset in pixels. 360: * 361: * @param offset the scroll offset 362: */ 363: public void setScrollOffset(int offset) 364: { 365: //FIXME: this should actualy scroll the field if needed 366: scrollOffset = offset; 367: } 368: 369: /** 370: * Returns the set of Actions that are commands for the editor. 371: * This is the actions supported by this editor plus the actions 372: * of the UI (returned by JTextComponent.getActions()). 373: */ 374: public Action[] getActions() 375: { 376: return TextAction.augmentList(super.getActions(), actions); 377: } 378: 379: public void postActionEvent() 380: { 381: String command = actionCommand != null ? actionCommand : getText(); 382: ActionEvent event = new ActionEvent(this, 0, command); 383: ActionListener[] listeners = getActionListeners(); 384: 385: for (int index = 0; index < listeners.length; ++index) 386: listeners[index].actionPerformed(event); 387: } 388: 389: /** 390: * @since 1.3 391: */ 392: public Action getAction() 393: { 394: return action; 395: } 396: 397: /** 398: * @since 1.3 399: */ 400: public void setAction(Action newAction) 401: { 402: if (action == newAction) 403: return; 404: 405: if (action != null) 406: { 407: removeActionListener(action); 408: action.removePropertyChangeListener(actionPropertyChangeListener); 409: actionPropertyChangeListener = null; 410: } 411: 412: Action oldAction = action; 413: action = newAction; 414: 415: if (action != null) 416: { 417: addActionListener(action); 418: actionPropertyChangeListener = createActionPropertyChangeListener(action); 419: action.addPropertyChangeListener(actionPropertyChangeListener); 420: } 421: 422: //FIXME: is this a hack? The horizontal alignment hasn't changed 423: firePropertyChange("horizontalAlignment", oldAction, newAction); 424: } 425: 426: /** 427: * Sets the command string used in action events. 428: * @since 1.3 429: */ 430: public void setActionCommand(String command) 431: { 432: actionCommand = command; 433: } 434: 435: /** 436: * @since 1.3 437: */ 438: protected PropertyChangeListener createActionPropertyChangeListener(Action action) 439: { 440: return new PropertyChangeListener() 441: { 442: public void propertyChange(PropertyChangeEvent event) 443: { 444: // Update properties "action" and "horizontalAlignment". 445: String name = event.getPropertyName(); 446: 447: if (name.equals("enabled")) 448: { 449: boolean enabled = ((Boolean) event.getNewValue()).booleanValue(); 450: JTextField.this.setEnabled(enabled); 451: } 452: else if (name.equals(Action.SHORT_DESCRIPTION)) 453: { 454: JTextField.this.setToolTipText((String) event.getNewValue()); 455: } 456: } 457: }; 458: } 459: 460: /** 461: * 462: * @since 1.3 463: */ 464: protected void configurePropertiesFromAction(Action action) 465: { 466: if (action != null) 467: { 468: setEnabled(action.isEnabled()); 469: setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION)); 470: } 471: else 472: { 473: setEnabled(true); 474: setToolTipText(null); 475: } 476: } 477: 478: /** 479: * Returns the column width, which is the width of the character m 480: * for the font in use. 481: * @return the width of the character m for the font in use. 482: */ 483: protected int getColumnWidth() 484: { 485: FontMetrics metrics = getToolkit().getFontMetrics(getFont()); 486: return metrics.charWidth('m'); 487: } 488: 489: /** 490: * Returns the accessible context associated with the <code>JTextField</code>. 491: * 492: * @return the accessible context associated with the <code>JTextField</code> 493: */ 494: public AccessibleContext getAccessibleContext() 495: { 496: if (accessibleContext == null) 497: accessibleContext = new AccessibleJTextField(); 498: return accessibleContext; 499: } 500: 501: /** 502: * Returns the bounded range model that describes the horizontal visibility 503: * of the text field in the case when the text does not fit into the 504: * available space. The actual values of this model are managed by the look 505: * and feel implementation. 506: * 507: * @return the bounded range model that describes the horizontal visibility 508: */ 509: public BoundedRangeModel getHorizontalVisibility() 510: { 511: // TODO: The real implementation of this property is still missing. 512: // However, this is not done in JTextField but must instead be handled in 513: // javax.swing.text.FieldView. 514: return horizontalVisibility; 515: } 516: }