001    /* TextField.java -- A one line text entry field
002       Copyright (C) 1999, 2002, 2004, 2006,  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import java.awt.event.ActionEvent;
042    import java.awt.event.ActionListener;
043    import java.awt.peer.ComponentPeer;
044    import java.awt.peer.TextFieldPeer;
045    import java.util.EventListener;
046    
047    import javax.accessibility.AccessibleContext;
048    import javax.accessibility.AccessibleStateSet;
049    
050    /**
051     * This class implements a single line text entry field widget
052     *
053     * @author Aaron M. Renn (arenn@urbanophile.com)
054     */
055    public class TextField extends TextComponent
056    {
057      
058      /**
059       * The number used to generate the name returned by getName.
060       */
061      private static transient long next_textfield_number;
062    
063      
064      private static final long serialVersionUID = -2966288784432217853L;
065    
066    
067      /**
068       * @serial The number of columns in the text entry field.
069       */
070      private int columns;
071    
072      /**
073       * @serial The character that is echoed when doing protected input
074       */
075      private char echoChar;
076    
077      // List of registered ActionListener's for this object.
078      private ActionListener action_listeners;
079    
080      /**
081       * Initializes a new instance of <code>TextField</code> that is empty
082       * and has one column.
083       *
084       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true,
085       */
086      public TextField()
087      {
088        this("", 0);
089      }
090    
091      /**
092       * Initializes a new instance of <code>TextField</code> containing
093       * the specified text.  The number of columns will be equal to the
094       * length of the text string.
095       *
096       * @param text The text to display in the field.
097       *
098       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true,
099       */
100      public TextField(String text)
101      {
102        this(text, (text == null) ? 0 : text.length());
103      }
104    
105      /**
106       * Initializes a new instance of <code>TextField</code> that is empty
107       * and has the specified number of columns.
108       *
109       * @param columns The number of columns in the text field.
110       *
111       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true,
112       */
113      public TextField(int columns)
114      {
115        this("", columns);
116      }
117    
118      /**
119       * Initializes a new instance of <code>TextField</code> with the
120       * specified text and number of columns.
121       *
122       * @param text The text to display in the field.
123       * @param columns The number of columns in the field.
124       *
125       * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true,
126       */
127      public TextField(String text, int columns)
128      {
129        super(text);
130      
131        if (columns < 0)
132          this.columns = 0;
133        else
134          this.columns = columns;
135    
136        if (GraphicsEnvironment.isHeadless())
137          throw new HeadlessException ();
138      }
139    
140      /**
141       * Returns the number of columns in the field.
142       *
143       * @return The number of columns in the field.
144       */
145      public int getColumns()
146      {
147        return(columns);
148      }
149    
150      /**
151       * Sets the number of columns in this field to the specified value.
152       *
153       * @param columns The new number of columns in the field.
154       *
155       * @exception IllegalArgumentException If columns is less than zero.
156       */
157      public synchronized void setColumns(int columns)
158      {
159        if (columns < 0)
160          throw new IllegalArgumentException("Value is less than zero: " +
161                                             columns);
162    
163        this.columns = columns;
164        // FIXME: How to we communicate this to our peer?
165      }
166    
167      /**
168       * Returns the character that is echoed to the screen when a text 
169       * field is protected (such as when a password is being entered).
170       *
171       * @return The echo character for this text field.
172       */
173      public char getEchoChar()
174      {
175        return(echoChar);
176      }
177    
178      /**
179       * Sets the character that is echoed when protected input such as
180       * a password is displayed.
181       *
182       * @param echoChar The new echo character.
183       */
184      public void setEchoChar(char echoChar)
185      {
186        setEchoCharacter(echoChar);
187      }
188    
189      /**
190       * Sets the character that is echoed when protected input such as
191       * a password is displayed.
192       *
193       * @param echoChar The new echo character.
194       *
195       * @deprecated This method is deprecated in favor of 
196       * <code>setEchoChar()</code>
197       */
198      public void setEchoCharacter(char echoChar)
199      {
200        this.echoChar = echoChar;
201    
202        TextFieldPeer peer = (TextFieldPeer) getPeer ();
203        if (peer != null)
204          peer.setEchoChar (echoChar);
205      }
206    
207      /**
208       * Tests whether or not this text field has an echo character set
209       * so that characters the user type are not echoed to the screen.
210       *
211       * @return <code>true</code> if an echo character is set,
212       * <code>false</code> otherwise.
213       */
214      public boolean echoCharIsSet()
215      {
216        if (echoChar == '\u0000')
217          return(false);
218        else
219          return(true);
220      }
221    
222      /**
223       * Returns the minimum size for this text field.
224       *
225       * @return The minimum size for this text field.
226       */
227      public Dimension getMinimumSize()
228      {
229        return getMinimumSize (getColumns ());
230      }
231    
232      /**
233       * Returns the minimum size of a text field with the specified number
234       * of columns.
235       *
236       * @param columns The number of columns to get the minimum size for.
237       */
238      public Dimension getMinimumSize(int columns)
239      {
240        return minimumSize(columns);
241      }
242    
243      /**
244       * Returns the minimum size for this text field.
245       *
246       * @return The minimum size for this text field.
247       *
248       * @deprecated This method is deprecated in favor of
249       * <code>getMinimumSize()</code>.
250       */
251      public Dimension minimumSize()
252      {
253        return minimumSize(getColumns ());
254      }
255    
256      /**
257       * Returns the minimum size of a text field with the specified number
258       * of columns.
259       *
260       * @param columns The number of columns to get the minimum size for.
261       *
262       * @deprecated This method is deprecated in favor of 
263       * <code>getMinimumSize(int)</code>.
264       */
265      public Dimension minimumSize(int columns)
266      {
267        if (isMinimumSizeSet())
268          return new Dimension(minSize);
269        
270        TextFieldPeer peer = (TextFieldPeer) getPeer ();
271        if (peer == null)
272          return new Dimension(getWidth(), getHeight());
273    
274        return peer.getMinimumSize (columns);
275      }
276    
277      /**
278       * Returns the preferred size for this text field.
279       *
280       * @return The preferred size for this text field.
281       */
282      public Dimension getPreferredSize()
283      {
284        return getPreferredSize(getColumns ());
285      }
286    
287      /**
288       * Returns the preferred size of a text field with the specified number
289       * of columns.
290       *
291       * @param columns The number of columns to get the preferred size for.
292       */
293      public Dimension getPreferredSize(int columns)
294      {
295        return preferredSize(columns);
296      }
297    
298      /**
299       * Returns the preferred size for this text field.
300       *
301       * @return The preferred size for this text field.
302       *
303       * @deprecated This method is deprecated in favor of 
304       * <code>getPreferredSize()</code>.
305       */
306      public Dimension preferredSize()
307      {
308        return preferredSize(getColumns ());
309      }
310    
311      /**
312       * Returns the preferred size of a text field with the specified number
313       * of columns.
314       *
315       * @param columns The number of columns to get the preferred size for.
316       *
317       * @deprecated This method is deprecated in favor of 
318       * <code>getPreferredSize(int)</code>.
319       */
320      public Dimension preferredSize(int columns)
321      {
322        if (isPreferredSizeSet())
323          return new Dimension(prefSize);
324        
325        TextFieldPeer peer = (TextFieldPeer) getPeer ();
326        if (peer == null)
327          return new Dimension (getWidth(), getHeight());
328        
329        return peer.getPreferredSize (columns);
330      }
331    
332      /**
333       * Notifies this object that it should create its native peer.
334       */
335      public void addNotify()
336      {
337        if (getPeer() != null)
338          return;
339    
340        setPeer((ComponentPeer)getToolkit().createTextField(this));
341        super.addNotify();
342      }
343    
344      /**
345       * Addes a new listener to the list of action listeners for this
346       * object.
347       *
348       * @param listener The listener to add to the list.
349       */
350      public synchronized void addActionListener(ActionListener listener)
351      {
352        action_listeners = AWTEventMulticaster.add(action_listeners, listener);
353    
354        enableEvents(AWTEvent.ACTION_EVENT_MASK);
355      }
356    
357      /**
358       * Removes the specified listener from the list of action listeners
359       * for this object.
360       *
361       * @param listener The listener to remove from the list.
362       */
363      public synchronized void removeActionListener(ActionListener listener)
364      {
365        action_listeners = AWTEventMulticaster.remove(action_listeners, listener);
366      }
367    
368      /**
369       * Processes the specified event.  If the event is an instance of
370       * <code>ActionEvent</code> then <code>processActionEvent()</code> is
371       * called to process it, otherwise the event is sent to the
372       * superclass.
373       *
374       * @param event The event to process.
375       */
376      protected void processEvent(AWTEvent event)
377      {
378        if (event instanceof ActionEvent)
379          processActionEvent((ActionEvent)event);
380        else
381          super.processEvent(event);
382      }
383    
384      /**
385       * Processes an action event by calling any registered listeners.
386       * Note to subclasses: This method is not called unless action events
387       * are enabled on this object.  This will be true if any listeners
388       * are registered, or if action events were specifically enabled
389       * using <code>enableEvents()</code>.
390       * 
391       * @param event The event to process.
392       */
393      protected void processActionEvent(ActionEvent event)
394      {
395        if (action_listeners != null)
396          action_listeners.actionPerformed(event);
397      }
398    
399      void dispatchEventImpl(AWTEvent e)
400      {
401        if (e.id <= ActionEvent.ACTION_LAST 
402            && e.id >= ActionEvent.ACTION_FIRST
403            && (action_listeners != null 
404                || (eventMask & AWTEvent.ACTION_EVENT_MASK) != 0))
405          processEvent(e);
406        else
407          super.dispatchEventImpl(e);
408      }
409    
410     /**
411      * Returns a debug string for this object.
412      *
413      * @return A debug string for this object.
414      */
415      protected String paramString()
416      {
417        return(getClass().getName() + "(columns=" + getColumns() + ",echoChar=" +
418               getEchoChar());
419      }
420    
421      /**
422       * Returns an array of all the objects currently registered as FooListeners
423       * upon this <code>TextField</code>. FooListeners are registered using the
424       * addFooListener method.
425       *
426       * @exception ClassCastException If listenerType doesn't specify a class or
427       * interface that implements java.util.EventListener.
428       *
429       * @since 1.3
430       */
431      public <T extends EventListener> T[] getListeners (Class<T> listenerType)
432      {
433        if (listenerType == ActionListener.class)
434          return AWTEventMulticaster.getListeners (action_listeners, listenerType);
435    
436        return super.getListeners (listenerType);
437      }
438    
439      /**
440       * Return all ActionListeners register to this <code>TextField</code> object
441       * as an array.
442       *
443       * @since 1.4
444       */
445      public ActionListener[] getActionListeners ()
446      {
447        return (ActionListener[]) getListeners (ActionListener.class);
448      }
449      
450      /**
451       * Generate a unique name for this <code>TextField</code>.
452       *
453       * @return A unique name for this <code>TextField</code>.
454       */
455      String generateName()
456      {
457        return "textfield" + getUniqueLong();
458      }
459    
460      private static synchronized long getUniqueLong()
461      {
462        return next_textfield_number++;
463      }
464    
465      protected class AccessibleAWTTextField extends AccessibleAWTTextComponent
466      {
467        private static final long serialVersionUID = 6219164359235943158L;
468    
469        protected AccessibleAWTTextField()
470        {
471        }
472        
473        public AccessibleStateSet getAccessibleStateSet()
474        {
475          return super.getAccessibleStateSet();
476        }
477      }
478      
479      public AccessibleContext getAccessibleContext()
480      {
481        return new AccessibleAWTTextField();
482      }
483    
484    }