View Javadoc

1   /*
2   Wotonomy: OpenStep design patterns for pure Java applications.
3   Copyright (C) 2000 Blacksmith, Inc.
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, see http://www.gnu.org
17  */
18  
19  package net.wotonomy.ui.swing.components;
20  
21  import java.awt.AWTEventMulticaster;
22  import java.awt.Component;
23  import java.awt.event.ActionEvent;
24  import java.awt.event.ActionListener;
25  import java.awt.event.KeyEvent;
26  import java.awt.event.KeyListener;
27  
28  import javax.swing.Timer;
29  
30  /***
31  * KeyDelayTimer is a utility that listens for KeyEvents from one
32  * or more components.  After receiving a KeyEvents the timer will
33  * broadcast an action event if a specified time interval passes without
34  * a subsequent KeyEvent.<BR><BR>
35  *
36  * This utility is useful for implementing any kind of auto-complete
37  * feature in a user interface.
38  *
39  * @author michael@mpowers.net
40  * @author $Author: cgruber $
41  * @version $Revision: 904 $
42  * $Date: 2006-02-18 23:19:05 +0000 (Sat, 18 Feb 2006) $
43  */
44  public class KeyDelayTimer implements ActionListener, KeyListener
45  {
46      // delay timer for keypress-sensitve events
47      protected Timer keyTimer = null;
48      protected Component lastFieldTouched = null;
49      protected long timeLastFieldTouched = 0;
50      protected int interval = 400; // adjust as needed
51  
52      // for action multicasting
53      protected ActionListener actionListener = null;
54  
55  /***
56  *   Default constructor.
57  */
58      public KeyDelayTimer()
59      {
60          keyTimer = new Timer( interval, this );
61      }
62  
63  /***
64  *   Convenience constructor.
65  *   @param listener An action listener to be notified of delay events.
66  */
67      public KeyDelayTimer( ActionListener listener )
68      {
69          this();
70          addActionListener( listener );
71      }
72  
73  /***
74  *   Returns the last component that generated a KeyEvent.
75  *   @return The component that sent the most recent KeyEvent.
76  */
77      public Component getComponent()
78      {
79          return lastFieldTouched;
80      }
81  
82  /***
83  *   Returns the number of milliseconds before an ActionEvent is generated.
84  *   The default is 400.
85  *   @return The current delay interval in milliseconds.
86  */
87      public int getInterval()
88      {
89          return interval;
90      }
91  
92  /***
93  *   Sets the number of milliseconds before an ActionEvent will be generated
94  *   after a KeyEvent is received.
95  *   @param millis The new delay interval in milliseconds.
96  */
97      public void setInterval( int millis )
98      {
99          interval = millis;
100         keyTimer.setDelay( interval / 2 );
101     }
102 
103     // interface KeyListener
104 
105     public void keyTyped(KeyEvent e)
106     {
107     }
108     public void keyPressed(KeyEvent e)
109     {
110     }
111 
112 /***
113 *   Receives key events from one or more components.
114 *   Records the component and the time this event was received,
115 *   then starts the timer.
116 *   @param e The key event in question.
117 */
118     public void keyReleased(KeyEvent e)
119     { // handles keystrokes in the textfields (except ENTER and ESCAPE)
120         if ( ( Character.isLetterOrDigit( e.getKeyChar() ) )
121         ||   ( e.getKeyCode() == KeyEvent.VK_SPACE )
122         ||   ( e.getKeyCode() == KeyEvent.VK_DELETE )
123         ||   ( e.getKeyCode() == KeyEvent.VK_BACK_SPACE ) )
124         {
125             this.lastFieldTouched = e.getComponent();
126             this.timeLastFieldTouched = System.currentTimeMillis();
127             this.keyTimer.start();
128             return;
129         }
130     }
131 
132     // interface ActionListener
133 
134 /***
135 *   Receives ActionEvents from the internal timer.
136 *   If the interval has passed without another KeyEvent,
137 *   an ActionEvent is broadcast, with the name of this class
138 *   as the ActionCommand, and the internal timer is stopped.
139 *   @param e The action event in question.
140 */
141      public void actionPerformed(ActionEvent e)
142      {
143         if ( e.getSource() == keyTimer )
144         {
145             if ( System.currentTimeMillis() - this.timeLastFieldTouched > interval )
146             {
147                 this.keyTimer.stop();
148                 broadcastEvent( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, this.getClass().getName() ) );
149             }
150             return;
151         }
152     }
153 
154     // Action Multicast methods
155 
156 /***
157 * Adds an action listener to the list that will be
158 * notified by button events and changes in button state.
159 * @param l An action listener to be notified.
160 */
161      public void addActionListener(ActionListener l)
162      {
163            actionListener = AWTEventMulticaster.add(actionListener, l);
164      }
165 /***
166 * Removes an action listener from the list that will be
167 * notified by button events and changes in button state.
168 * @param l An action listener to be removed.
169 */
170      public void removeActionListener(ActionListener l)
171      {
172            actionListener = AWTEventMulticaster.remove(actionListener, l);
173      }
174 /***
175 * Notifies all registered action listeners of a pending Action Event.
176 * @param e An action event to be broadcast.
177 */
178      protected void broadcastEvent(ActionEvent e)
179      {
180          if (actionListener != null)
181          {
182              actionListener.actionPerformed(e);
183          }
184      }
185 
186 }
187 
188