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