Frames | No Frames |
1: /* Timer.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.event.ActionEvent; 42: import java.awt.event.ActionListener; 43: import java.io.Serializable; 44: import java.util.EventListener; 45: 46: import javax.swing.event.EventListenerList; 47: 48: /** 49: * Fires one or more action events after the specified delay. This is 50: * a specialised version of <code>java.util.Timer</code> just for 51: * firing <code>ActionEvent</code>s. All Timers share one (daemon) 52: * Thread (or java.util.Timer). All events are fired from the event 53: * queue. 54: * 55: * @author Ronald Veldema 56: * @author Audrius Meskauskas (audriusa@Bionformatics.org) - bug fixes 57: * and documentation comments 58: */ 59: public class Timer 60: implements Serializable 61: { 62: /** 63: * Given to the shared java.util.Timer to (possibly repeatedly) call 64: * queueEvent(). 65: */ 66: private class Task extends java.util.TimerTask 67: { 68: public void run() 69: { 70: if (logTimers) 71: System.out.println("javax.swing.Timer -> queueEvent()"); 72: queueEvent(); 73: 74: if (!repeats) 75: task = null; 76: } 77: } 78: 79: /** 80: * Use serialVersionUID for interoperability. 81: */ 82: private static final long serialVersionUID = -1116180831621385484L; 83: 84: /** 85: * The encloding class, used with {@link SwingUtilities#invokeLater} 86: * to invoke the {@link #drainEvents()}. 87: */ 88: private Runnable drainer = new Runnable() 89: { 90: public void run() 91: { 92: drainEvents(); 93: } 94: }; 95: 96: /** 97: * The static java.util.Timer daemon which will be used to schedule 98: * all javax.swing.Timer.Task objects. The daemon will always be 99: * running, even if there's no task scheduled in it. 100: */ 101: private static java.util.Timer timer = new java.util.Timer("swing.Timer", 102: true); 103: 104: /** 105: * If <code>true</code>, the timer prints a message to 106: * {@link System#out} when firing each event. 107: */ 108: static boolean logTimers; 109: 110: /** 111: * A field to store all listeners who are listening to this timer. 112: */ 113: protected EventListenerList listenerList = new EventListenerList(); 114: 115: /** 116: * <code>true</code> if the timer coalesces events. 117: */ 118: boolean coalesce = true; 119: 120: /** 121: * <code>true</code> if the timer is firing repetetive events. 122: */ 123: boolean repeats = true; 124: 125: /** 126: * The delay between subsequent repetetive events. 127: */ 128: int delay; 129: 130: /** 131: * The initial delay before the first event. 132: */ 133: int initialDelay; 134: 135: /** 136: * The number of events that have been already fired by this timer. 137: * This is used as a numeric identifier for the next event that would 138: * be fired. 139: */ 140: int ticks; 141: 142: /** 143: * The task that calls queueEvent(). When null this Timer is stopped. 144: * This is package private to avoid synthetic accessor method. 145: */ 146: Task task; 147: 148: /** 149: * This object manages a "queue" of virtual actionEvents, maintained as a 150: * simple long counter. When the timer expires, a new event is queued, 151: * and a dispatcher object is pushed into the system event queue. When 152: * the system thread runs the dispatcher, it will fire as many 153: * ActionEvents as have been queued, unless the timer is set to 154: * coalescing mode, in which case it will fire only one ActionEvent. 155: */ 156: private long queue; 157: 158: /** 159: * <code>synchronized(queueLock)</code> replaces 160: * <code>synchronized(queue)</code> that is not supported by this language. 161: */ 162: private Object queueLock = new Object(); 163: 164: /** 165: * Creates a new Timer object. 166: * 167: * @param d the default value for both initial and between event delay, in 168: * milliseconds. 169: * @param listener the first action listener, can be <code>null</code>. 170: */ 171: public Timer(int d, ActionListener listener) 172: { 173: delay = d; 174: initialDelay = d; 175: 176: if (listener != null) 177: addActionListener(listener); 178: } 179: 180: /** 181: * Get the array of action listeners. 182: * 183: * @return the array of action listeners that are listening for the events, 184: * fired by this timer 185: * 186: * @since 1.4 187: */ 188: public ActionListener[] getActionListeners() 189: { 190: return (ActionListener[]) listenerList.getListeners(ActionListener.class); 191: } 192: 193: /** 194: * Sets whether the Timer coalesces multiple pending event firings. 195: * If the coalescing is enabled, the multiple events that have not been 196: * fired on time are replaced by the single event. The events may not 197: * be fired on time if the application is busy. 198: * 199: * @param c <code>true</code> (default) to enable the event coalescing, 200: * <code>false</code> otherwise 201: */ 202: public void setCoalesce(boolean c) 203: { 204: coalesce = c; 205: } 206: 207: /** 208: * Checks if the Timer coalesces multiple pending event firings. 209: * If the coalescing is enabled, the multiple events that have not been 210: * fired on time are replaced by the single event. The events may not 211: * be fired on time if the application is busy. 212: * 213: * @return <code>true</code> if the coalescing is enabled, 214: * <code>false</code> otherwise 215: */ 216: public boolean isCoalesce() 217: { 218: return coalesce; 219: } 220: 221: /** 222: * Get the event listeners of the given type that are listening for the 223: * events, fired by this timer. 224: * 225: * @param listenerType the listener type (for example, ActionListener.class) 226: * 227: * @return the array of event listeners that are listening for the events, 228: * fired by this timer 229: * @since 1.3 230: */ 231: public EventListener[] getListeners(Class listenerType) 232: { 233: return listenerList.getListeners(listenerType); 234: } 235: 236: /** 237: * Set the timer logging state. If it is set to <code>true</code>, the 238: * timer prints a message to {@link System#out} when firing each 239: * action event. 240: * 241: * @param lt <code>true</code> if logging is enabled, <code>false</code> 242: * (default value) otherwise 243: */ 244: public static void setLogTimers(boolean lt) 245: { 246: logTimers = lt; 247: } 248: 249: /** 250: * Return the logging state. 251: * 252: * @return <code>true</code> if the timer is printing a message to 253: * {@link System#out} 254: * when firing each action event 255: */ 256: public static boolean getLogTimers() 257: { 258: return logTimers; 259: } 260: 261: /** 262: * Set the delay between firing the subsequent events. 263: * This parameter does not change the value of the initial delay before 264: * firing the first event. 265: * 266: * @param d The time gap between the subsequent events, in milliseconds 267: */ 268: public void setDelay(int d) 269: { 270: delay = d; 271: } 272: 273: /** 274: * Get the delay between firing the subsequent events. 275: * 276: * @return The delay between subsequent events, in milliseconds 277: */ 278: public int getDelay() 279: { 280: return delay; 281: } 282: 283: /** 284: * Set the intial delay before firing the first event since calling 285: * the {@link #start()} method. If the initial delay has not been 286: * set, it is assumed having the same value as the delay between the 287: * subsequent events. 288: * 289: * @param i the initial delay, in milliseconds 290: */ 291: public void setInitialDelay(int i) 292: { 293: initialDelay = i; 294: } 295: 296: /** 297: * Get the intial delay before firing the first event since calling 298: * the {@link #start()} method. If the initial delay has not been 299: * set, returns the same value as {@link #getDelay()}. 300: * 301: * @return the initial delay before firing the first action event. 302: */ 303: public int getInitialDelay() 304: { 305: return initialDelay; 306: } 307: 308: /** 309: * Enable firing the repetetive events. 310: * 311: * @param r <code>true</code> (default value) to fire repetetive events. 312: * <code>false</code> to fire 313: * only one event after the initial delay 314: */ 315: public void setRepeats(boolean r) 316: { 317: repeats = r; 318: } 319: 320: /** 321: * Check is this timer fires repetetive events. 322: * 323: * @return <code>true</code> if the timer fires repetetive events, 324: * <code>false</code> if it fires 325: * only one event after the initial delay 326: */ 327: public boolean isRepeats() 328: { 329: return repeats; 330: } 331: 332: /** 333: * Get the timer state. 334: * 335: * @return <code>true</code> if the timer has been started and is firing 336: * the action events as scheduled. <code>false</code> 337: * if the timer is inactive. 338: */ 339: public boolean isRunning() 340: { 341: return task != null; 342: } 343: 344: /** 345: * Add the action listener 346: * 347: * @param listener the action listener to add 348: */ 349: public void addActionListener(ActionListener listener) 350: { 351: listenerList.add(ActionListener.class, listener); 352: } 353: 354: /** 355: * Remove the action listener. 356: * 357: * @param listener the action listener to remove 358: */ 359: public void removeActionListener(ActionListener listener) 360: { 361: listenerList.remove(ActionListener.class, listener); 362: } 363: 364: /** 365: * Cancel all pending tasks and fire the first event after the initial 366: * delay. 367: */ 368: public void restart() 369: { 370: stop(); 371: start(); 372: } 373: 374: /** 375: * Start firing the action events. 376: */ 377: public void start() 378: { 379: Task t = task; 380: if (t == null) 381: { 382: t = new Task(); 383: if (isRepeats()) 384: timer.schedule(t, getInitialDelay(), getDelay()); 385: else 386: timer.schedule(t, getInitialDelay()); 387: task = t; 388: } 389: } 390: 391: /** 392: * Stop firing the action events. 393: */ 394: public void stop() 395: { 396: Task t = task; 397: if (t != null) 398: { 399: t.cancel(); 400: task = null; 401: } 402: } 403: 404: /** 405: * Fire the given action event to the action listeners. 406: * 407: * @param event the event to fire 408: */ 409: protected void fireActionPerformed(ActionEvent event) 410: { 411: ActionListener[] listeners = getActionListeners(); 412: 413: for (int i = 0; i < listeners.length; i++) 414: listeners [ i ].actionPerformed(event); 415: } 416: 417: /** 418: * Fire the action event, named "Timer" and having the numeric 419: * identifier, equal to the numer of events that have been 420: * already fired before. 421: */ 422: void fireActionPerformed() 423: { 424: fireActionPerformed(new ActionEvent(this, ticks++, "Timer")); 425: } 426: 427: /** 428: * Fire the queued action events. 429: * In the coalescing mode, a single event is fired as a replacement 430: * for all queued events. In non coalescing mode, a series of 431: * all queued events is fired. 432: * This is package-private to avoid an accessor method. 433: */ 434: void drainEvents() 435: { 436: synchronized (queueLock) 437: { 438: if (isCoalesce()) 439: { 440: if (queue > 0) 441: fireActionPerformed(); 442: } 443: else 444: { 445: while (queue > 0) 446: { 447: fireActionPerformed(); 448: queue--; 449: } 450: } 451: queue = 0; 452: } 453: } 454: 455: /** 456: * Post a scheduled event to the event queue. 457: * Package-private to avoid an accessor method. 458: */ 459: void queueEvent() 460: { 461: synchronized(queueLock) 462: { 463: queue++; 464: if (queue == 1) 465: SwingUtilities.invokeLater(drainer); 466: } 467: } 468: }