GNU Classpath (0.20) | |
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: */ 145: private Task task; 146: 147: /** 148: * This object manages a "queue" of virtual actionEvents, maintained as a 149: * simple long counter. When the timer expires, a new event is queued, 150: * and a dispatcher object is pushed into the system event queue. When 151: * the system thread runs the dispatcher, it will fire as many 152: * ActionEvents as have been queued, unless the timer is set to 153: * coalescing mode, in which case it will fire only one ActionEvent. 154: */ 155: private long queue; 156: 157: /** 158: * <code>synchronized(queueLock)</code> replaces 159: * <code>synchronized(queue)</code> that is not supported by this language. 160: */ 161: private Object queueLock = new Object(); 162: 163: /** 164: * Creates a new Timer object. 165: * 166: * @param d the default value for both initial and between event delay, in 167: * milliseconds. 168: * @param listener the first action listener, can be <code>null</code>. 169: */ 170: public Timer(int d, ActionListener listener) 171: { 172: delay = d; 173: initialDelay = d; 174: 175: if (listener != null) 176: addActionListener(listener); 177: } 178: 179: /** 180: * Get the array of action listeners. 181: * 182: * @return the array of action listeners that are listening for the events, 183: * fired by this timer 184: * 185: * @since 1.4 186: */ 187: public ActionListener[] getActionListeners() 188: { 189: return (ActionListener[]) listenerList.getListeners(ActionListener.class); 190: } 191: 192: /** 193: * Sets whether the Timer coalesces multiple pending event firings. 194: * If the coalescing is enabled, the multiple events that have not been 195: * fired on time are replaced by the single event. The events may not 196: * be fired on time if the application is busy. 197: * 198: * @param c <code>true</code> (default) to enable the event coalescing, 199: * <code>false</code> otherwise 200: */ 201: public void setCoalesce(boolean c) 202: { 203: coalesce = c; 204: } 205: 206: /** 207: * Checks if the Timer coalesces multiple pending event firings. 208: * If the coalescing is enabled, the multiple events that have not been 209: * fired on time are replaced by the single event. The events may not 210: * be fired on time if the application is busy. 211: * 212: * @return <code>true</code> if the coalescing is enabled, 213: * <code>false</code> otherwise 214: */ 215: public boolean isCoalesce() 216: { 217: return coalesce; 218: } 219: 220: /** 221: * Get the event listeners of the given type that are listening for the 222: * events, fired by this timer. 223: * 224: * @param listenerType the listener type (for example, ActionListener.class) 225: * 226: * @return the array of event listeners that are listening for the events, 227: * fired by this timer 228: * @since 1.3 229: */ 230: public EventListener[] getListeners(Class listenerType) 231: { 232: return listenerList.getListeners(listenerType); 233: } 234: 235: /** 236: * Set the timer logging state. If it is set to <code>true</code>, the 237: * timer prints a message to {@link System#out} when firing each 238: * action event. 239: * 240: * @param lt <code>true</code> if logging is enabled, <code>false</code> 241: * (default value) otherwise 242: */ 243: public static void setLogTimers(boolean lt) 244: { 245: logTimers = lt; 246: } 247: 248: /** 249: * Return the logging state. 250: * 251: * @return <code>true</code> if the timer is printing a message to 252: * {@link System#out} 253: * when firing each action event 254: */ 255: public static boolean getLogTimers() 256: { 257: return logTimers; 258: } 259: 260: /** 261: * Set the delay between firing the subsequent events. 262: * This parameter does not change the value of the initial delay before 263: * firing the first event. 264: * 265: * @param d The time gap between the subsequent events, in milliseconds 266: */ 267: public void setDelay(int d) 268: { 269: delay = d; 270: } 271: 272: /** 273: * Get the delay between firing the subsequent events. 274: * 275: * @return The delay between subsequent events, in milliseconds 276: */ 277: public int getDelay() 278: { 279: return delay; 280: } 281: 282: /** 283: * Set the intial delay before firing the first event since calling 284: * the {@link #start()} method. If the initial delay has not been 285: * set, it is assumed having the same value as the delay between the 286: * subsequent events. 287: * 288: * @param i the initial delay, in milliseconds 289: */ 290: public void setInitialDelay(int i) 291: { 292: initialDelay = i; 293: } 294: 295: /** 296: * Get the intial delay before firing the first event since calling 297: * the {@link #start()} method. If the initial delay has not been 298: * set, returns the same value as {@link #getDelay()}. 299: * 300: * @return the initial delay before firing the first action event. 301: */ 302: public int getInitialDelay() 303: { 304: return initialDelay; 305: } 306: 307: /** 308: * Enable firing the repetetive events. 309: * 310: * @param r <code>true</code> (default value) to fire repetetive events. 311: * <code>false</code> to fire 312: * only one event after the initial delay 313: */ 314: public void setRepeats(boolean r) 315: { 316: repeats = r; 317: } 318: 319: /** 320: * Check is this timer fires repetetive events. 321: * 322: * @return <code>true</code> if the timer fires repetetive events, 323: * <code>false</code> if it fires 324: * only one event after the initial delay 325: */ 326: public boolean isRepeats() 327: { 328: return repeats; 329: } 330: 331: /** 332: * Get the timer state. 333: * 334: * @return <code>true</code> if the timer has been started and is firing 335: * the action events as scheduled. <code>false</code> 336: * if the timer is inactive. 337: */ 338: public boolean isRunning() 339: { 340: return task != null; 341: } 342: 343: /** 344: * Add the action listener 345: * 346: * @param listener the action listener to add 347: */ 348: public void addActionListener(ActionListener listener) 349: { 350: listenerList.add(ActionListener.class, listener); 351: } 352: 353: /** 354: * Remove the action listener. 355: * 356: * @param listener the action listener to remove 357: */ 358: public void removeActionListener(ActionListener listener) 359: { 360: listenerList.remove(ActionListener.class, listener); 361: } 362: 363: /** 364: * Cancel all pending tasks and fire the first event after the initial 365: * delay. 366: */ 367: public void restart() 368: { 369: stop(); 370: start(); 371: } 372: 373: /** 374: * Start firing the action events. 375: */ 376: public void start() 377: { 378: Task t = task; 379: if (t == null) 380: { 381: t = new Task(); 382: if (isRepeats()) 383: timer.schedule(t, getInitialDelay(), getDelay()); 384: else 385: timer.schedule(t, getInitialDelay()); 386: task = t; 387: } 388: } 389: 390: /** 391: * Stop firing the action events. 392: */ 393: public void stop() 394: { 395: Task t = task; 396: if (t != null) 397: { 398: t.cancel(); 399: task = null; 400: } 401: } 402: 403: /** 404: * Fire the given action event to the action listeners. 405: * 406: * @param event the event to fire 407: */ 408: protected void fireActionPerformed(ActionEvent event) 409: { 410: ActionListener[] listeners = getActionListeners(); 411: 412: for (int i = 0; i < listeners.length; i++) 413: listeners [ i ].actionPerformed(event); 414: } 415: 416: /** 417: * Fire the action event, named "Timer" and having the numeric 418: * identifier, equal to the numer of events that have been 419: * already fired before. 420: */ 421: void fireActionPerformed() 422: { 423: fireActionPerformed(new ActionEvent(this, ticks++, "Timer")); 424: } 425: 426: /** 427: * Fire the queued action events. 428: * In the coalescing mode, a single event is fired as a replacement 429: * for all queued events. In non coalescing mode, a series of 430: * all queued events is fired. 431: * This is package-private to avoid an accessor method. 432: */ 433: void drainEvents() 434: { 435: synchronized (queueLock) 436: { 437: if (isCoalesce()) 438: { 439: if (queue > 0) 440: fireActionPerformed(); 441: } 442: else 443: { 444: while (queue > 0) 445: { 446: fireActionPerformed(); 447: queue--; 448: } 449: } 450: queue = 0; 451: } 452: } 453: 454: /** 455: * Post a scheduled event to the event queue. 456: * Package-private to avoid an accessor method. 457: */ 458: void queueEvent() 459: { 460: synchronized(queueLock) 461: { 462: queue++; 463: if (queue == 1) 464: SwingUtilities.invokeLater(drainer); 465: } 466: } 467: }
GNU Classpath (0.20) |