Source for javax.swing.Timer

   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: }