GNU Classpath (0.95) | |
Frames | No Frames |
1: /* Timer.java -- 2: Copyright (C) 2002, 2004, 2005, 2006, 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 <T extends EventListener> T[] getListeners(Class<T> 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: * @throws IllegalArgumentException if <code>d</code> is less than zero. 269: */ 270: public void setDelay(int d) 271: { 272: if (d < 0) 273: throw new IllegalArgumentException("Invalid delay: " + d); 274: delay = d; 275: } 276: 277: /** 278: * Get the delay between firing the subsequent events. 279: * 280: * @return The delay between subsequent events, in milliseconds 281: */ 282: public int getDelay() 283: { 284: return delay; 285: } 286: 287: /** 288: * Set the intial delay before firing the first event since calling 289: * the {@link #start()} method. If the initial delay has not been 290: * set, it is assumed having the same value as the delay between the 291: * subsequent events. 292: * 293: * @param i the initial delay, in milliseconds 294: * 295: * @throws IllegalArgumentException if <code>i</code> is less than zero. 296: */ 297: public void setInitialDelay(int i) 298: { 299: if (i < 0) 300: throw new IllegalArgumentException("Invalid initial delay: " + i); 301: initialDelay = i; 302: } 303: 304: /** 305: * Get the intial delay before firing the first event since calling 306: * the {@link #start()} method. If the initial delay has not been 307: * set, returns the same value as {@link #getDelay()}. 308: * 309: * @return the initial delay before firing the first action event. 310: */ 311: public int getInitialDelay() 312: { 313: return initialDelay; 314: } 315: 316: /** 317: * Enable firing the repetetive events. 318: * 319: * @param r <code>true</code> (default value) to fire repetetive events. 320: * <code>false</code> to fire 321: * only one event after the initial delay 322: */ 323: public void setRepeats(boolean r) 324: { 325: repeats = r; 326: } 327: 328: /** 329: * Check is this timer fires repetetive events. 330: * 331: * @return <code>true</code> if the timer fires repetetive events, 332: * <code>false</code> if it fires 333: * only one event after the initial delay 334: */ 335: public boolean isRepeats() 336: { 337: return repeats; 338: } 339: 340: /** 341: * Get the timer state. 342: * 343: * @return <code>true</code> if the timer has been started and is firing 344: * the action events as scheduled. <code>false</code> 345: * if the timer is inactive. 346: */ 347: public boolean isRunning() 348: { 349: return task != null; 350: } 351: 352: /** 353: * Add the action listener 354: * 355: * @param listener the action listener to add 356: */ 357: public void addActionListener(ActionListener listener) 358: { 359: listenerList.add(ActionListener.class, listener); 360: } 361: 362: /** 363: * Remove the action listener. 364: * 365: * @param listener the action listener to remove 366: */ 367: public void removeActionListener(ActionListener listener) 368: { 369: listenerList.remove(ActionListener.class, listener); 370: } 371: 372: /** 373: * Cancel all pending tasks and fire the first event after the initial 374: * delay. 375: */ 376: public void restart() 377: { 378: stop(); 379: start(); 380: } 381: 382: /** 383: * Start firing the action events. 384: */ 385: public void start() 386: { 387: Task t = task; 388: if (t == null) 389: { 390: t = new Task(); 391: if (isRepeats()) 392: timer.schedule(t, getInitialDelay(), getDelay()); 393: else 394: timer.schedule(t, getInitialDelay()); 395: task = t; 396: } 397: } 398: 399: /** 400: * Stop firing the action events. 401: */ 402: public void stop() 403: { 404: Task t = task; 405: if (t != null) 406: { 407: t.cancel(); 408: task = null; 409: } 410: } 411: 412: /** 413: * Fire the given action event to the action listeners. 414: * 415: * @param event the event to fire 416: */ 417: protected void fireActionPerformed(ActionEvent event) 418: { 419: ActionListener[] listeners = getActionListeners(); 420: 421: for (int i = 0; i < listeners.length; i++) 422: listeners [ i ].actionPerformed(event); 423: } 424: 425: /** 426: * Fire the action event, named "Timer" and having the numeric 427: * identifier, equal to the numer of events that have been 428: * already fired before. 429: */ 430: void fireActionPerformed() 431: { 432: fireActionPerformed(new ActionEvent(this, ticks++, "Timer")); 433: } 434: 435: /** 436: * Fire the queued action events. 437: * In the coalescing mode, a single event is fired as a replacement 438: * for all queued events. In non coalescing mode, a series of 439: * all queued events is fired. 440: * This is package-private to avoid an accessor method. 441: */ 442: void drainEvents() 443: { 444: synchronized (queueLock) 445: { 446: if (isCoalesce()) 447: { 448: if (queue > 0) 449: fireActionPerformed(); 450: } 451: else 452: { 453: while (queue > 0) 454: { 455: fireActionPerformed(); 456: queue--; 457: } 458: } 459: queue = 0; 460: } 461: } 462: 463: /** 464: * Post a scheduled event to the event queue. 465: * Package-private to avoid an accessor method. 466: */ 467: void queueEvent() 468: { 469: synchronized(queueLock) 470: { 471: queue++; 472: if (queue == 1) 473: SwingUtilities.invokeLater(drainer); 474: } 475: } 476: }
GNU Classpath (0.95) |