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