/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Blacksmith, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.ui.swing.components; import java.awt.AWTEventMulticaster; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.Timer; /** * KeyDelayTimer is a utility that listens for KeyEvents from one or more * components. After receiving a KeyEvents the timer will broadcast an action * event if a specified time interval passes without a subsequent KeyEvent.
*
* * This utility is useful for implementing any kind of auto-complete feature in * a user interface. * * @author michael@mpowers.net * @author $Author: cgruber $ * @version $Revision: 904 $ $Date: 2006-02-18 18:19:05 -0500 (Sat, 18 Feb 2006) * $ */ public class KeyDelayTimer implements ActionListener, KeyListener { // delay timer for keypress-sensitve events protected Timer keyTimer = null; protected Component lastFieldTouched = null; protected long timeLastFieldTouched = 0; protected int interval = 400; // adjust as needed // for action multicasting protected ActionListener actionListener = null; /** * Default constructor. */ public KeyDelayTimer() { keyTimer = new Timer(interval, this); } /** * Convenience constructor. * * @param listener An action listener to be notified of delay events. */ public KeyDelayTimer(ActionListener listener) { this(); addActionListener(listener); } /** * Returns the last component that generated a KeyEvent. * * @return The component that sent the most recent KeyEvent. */ public Component getComponent() { return lastFieldTouched; } /** * Returns the number of milliseconds before an ActionEvent is generated. The * default is 400. * * @return The current delay interval in milliseconds. */ public int getInterval() { return interval; } /** * Sets the number of milliseconds before an ActionEvent will be generated after * a KeyEvent is received. * * @param millis The new delay interval in milliseconds. */ public void setInterval(int millis) { interval = millis; keyTimer.setDelay(interval / 2); } // interface KeyListener public void keyTyped(KeyEvent e) { } public void keyPressed(KeyEvent e) { } /** * Receives key events from one or more components. Records the component and * the time this event was received, then starts the timer. * * @param e The key event in question. */ public void keyReleased(KeyEvent e) { // handles keystrokes in the textfields (except ENTER and ESCAPE) if ((Character.isLetterOrDigit(e.getKeyChar())) || (e.getKeyCode() == KeyEvent.VK_SPACE) || (e.getKeyCode() == KeyEvent.VK_DELETE) || (e.getKeyCode() == KeyEvent.VK_BACK_SPACE)) { this.lastFieldTouched = e.getComponent(); this.timeLastFieldTouched = System.currentTimeMillis(); this.keyTimer.start(); return; } } // interface ActionListener /** * Receives ActionEvents from the internal timer. If the interval has passed * without another KeyEvent, an ActionEvent is broadcast, with the name of this * class as the ActionCommand, and the internal timer is stopped. * * @param e The action event in question. */ public void actionPerformed(ActionEvent e) { if (e.getSource() == keyTimer) { if (System.currentTimeMillis() - this.timeLastFieldTouched > interval) { this.keyTimer.stop(); broadcastEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, this.getClass().getName())); } return; } } // Action Multicast methods /** * Adds an action listener to the list that will be notified by button events * and changes in button state. * * @param l An action listener to be notified. */ public void addActionListener(ActionListener l) { actionListener = AWTEventMulticaster.add(actionListener, l); } /** * Removes an action listener from the list that will be notified by button * events and changes in button state. * * @param l An action listener to be removed. */ public void removeActionListener(ActionListener l) { actionListener = AWTEventMulticaster.remove(actionListener, l); } /** * Notifies all registered action listeners of a pending Action Event. * * @param e An action event to be broadcast. */ protected void broadcastEvent(ActionEvent e) { if (actionListener != null) { actionListener.actionPerformed(e); } } }