home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / swing / Timer.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  10.5 KB  |  341 lines

  1. /*
  2.  * @(#)Timer.java    1.17 98/02/02
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21.  
  22. /**
  23.  * Allows objects to be notified at future intervals, using the
  24.  * ActionListener interface.
  25.  *
  26.  *
  27.  * @version 1.17 02/02/98
  28.  * @author Dave Moore
  29.  */
  30.  
  31. package java.awt.swing;
  32.  
  33. import java.util.*;
  34. import java.awt.*;
  35. import java.awt.event.*;
  36. import java.io.Serializable;
  37. import java.awt.swing.event.EventListenerList;
  38.  
  39.  
  40. /**
  41.  * Object subclass that causes an action to occur at a predefined rate.  For
  42.  * example, an animation object can use a JTimer as the trigger for drawing its
  43.  * next frame.  Each Timer has a list of ActionListeners and a delay (
  44.  * the time between <b>actionPerfomed()</b> calls).  When
  45.  * delay milliseconds have passed, a JTimer sends the <b>actionPerformed()</b>
  46.  * message to its listeners.  This cycle repeats until
  47.  * <b>stop()</b> is called, or halts immediately if the Jimer is configured
  48.  * to send its message just once.<p>
  49.  * Using a JTimer involves first creating it, then starting it using
  50.  * the <b>start()</b> method.
  51.  * <p>
  52.  * Warning: serialized objects of this class will not be compatible with
  53.  * future swing releases.  The current serialization support is appropriate 
  54.  * for short term storage or RMI between Swing1.0 applications.  It will
  55.  * not be possible to load serialized Swing1.0 objects with future releases
  56.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  57.  * baseline for the serialized form of Swing objects.
  58.  *
  59.  * @version 1.17 02/02/98
  60.  * @author unknown
  61.  */
  62. public class Timer implements Serializable
  63. {
  64.     int         initialDelay, delay;
  65.     boolean     repeats = true, coalesce = true;
  66.     private DummyComponent dummyComponent;
  67.     protected EventListenerList listenerList = new EventListenerList();
  68.     TimerEvent  queuedEvent;
  69.     static final int TIMER_ID = AWTEvent.RESERVED_ID_MAX + 1;
  70.     private static boolean logTimers;
  71.  
  72.     // These fields are maintained by TimerQueue.
  73.  
  74.     long expirationTime;
  75.     Timer nextTimer;
  76.     boolean running;
  77.  
  78.     /**
  79.      * Creates a JTimer that will notify its listeners every
  80.      * <i>delay</i> milliseconds.
  81.      * @param delay     The number of milliseconds between listener notification
  82.      * @param listener  An initial listener
  83.      * @see #setInitialDelay
  84.      * @see #setRepeats
  85.      */
  86.     public Timer(int delay, ActionListener listener) {
  87.         super();
  88.         this.delay = delay;
  89.         this.initialDelay = delay;
  90.         dummyComponent = new DummyComponent();
  91.         if (listener != null) {
  92.             addActionListener(listener);
  93.         }
  94.     }
  95.  
  96.     /**
  97.      * Adds an actionListener to the Timer
  98.      */
  99.     public void addActionListener(ActionListener listener) {
  100.         listenerList.add(ActionListener.class, listener);
  101.     }
  102.  
  103.     /**
  104.      * Removes an ActionListener from the Timer.
  105.      */
  106.     public void removeActionListener(ActionListener listener) {
  107.         listenerList.remove(ActionListener.class, listener);
  108.     }
  109.  
  110.     /*
  111.      * Notify all listeners that have registered interest for
  112.      * notification on this event type.  The event instance 
  113.      * is lazily created using the parameters passed into 
  114.      * the fire method.
  115.      * @see EventListenerList
  116.      */
  117.     protected void fireActionPerformed(ActionEvent e) {
  118.     // Guaranteed to return a non-null array
  119.     Object[] listeners = listenerList.getListenerList();
  120.     // Process the listeners last to first, notifying
  121.     // those that are interested in this event
  122.     for (int i = listeners.length-2; i>=0; i-=2) {
  123.         if (listeners[i]==ActionListener.class) {
  124.         ((ActionListener)listeners[i+1]).actionPerformed(e);
  125.         }           
  126.     }
  127.     }
  128.     
  129.     /** Returns the timer queue. */
  130.     TimerQueue timerQueue() {
  131.         return TimerQueue.sharedInstance();
  132.     }
  133.  
  134.     public static void setLogTimers(boolean flag) {
  135.         logTimers = flag;
  136.     }
  137.  
  138.     public static boolean getLogTimers() {
  139.         return logTimers;
  140.     }
  141.  
  142.     /** Sets the Timer's delay, the number of milliseconds between successive
  143.       * <b>actionPerfomed()</b> messages to its listeners
  144.       * @see #setInitialDelay
  145.       */
  146.     public void setDelay(int delay) {
  147.         TimerQueue queue;
  148.  
  149.         if (delay < 0) {
  150.             throw new RuntimeException("Invalid initial delay: " + delay);
  151.         }
  152.         this.delay = delay;
  153.  
  154.         if (isRunning()) {
  155.             queue = timerQueue();
  156.             queue.removeTimer(this);
  157.             cancelEvent();
  158.             queue.addTimer(this, System.currentTimeMillis() + delay);
  159.         }
  160.     }
  161.  
  162.     /** Returns the Timer's delay.
  163.       * @see #setDelay
  164.       */
  165.     public int getDelay() {
  166.         return delay;
  167.     }
  168.  
  169.     /** Sets the Timer's initial delay.  This will be used for the first
  170.       * "ringing" of the Timer only.  Subsequent ringings will be spaced
  171.       * using the delay property.
  172.       * @see #setDelay
  173.       */
  174.     public void setInitialDelay(int initialDelay) {
  175.         if (initialDelay < 0) {
  176.             throw new RuntimeException("Invalid initial delay: " +
  177.                                           initialDelay);
  178.         }
  179.         this.initialDelay = initialDelay;
  180.     }
  181.  
  182.     /** Returns the Timer's initial delay.
  183.       * @see #setDelay
  184.       */
  185.     public int getInitialDelay() {
  186.         return initialDelay;
  187.     }
  188.  
  189.     /** If <b>flag</b> is <b>false</b>, instructs the Timer to send
  190.       * <b>actionPerformed()</b> to its listeners only once, and then stop.
  191.       */
  192.     public void setRepeats(boolean flag) {
  193.         repeats = flag;
  194.     }
  195.  
  196.     /** Returns <b>true</b> if the Timer will send a <b>actionPerformed()</b>
  197.       * message to its listeners multiple times.
  198.       * @see #setRepeats
  199.       */
  200.     public boolean isRepeats() {
  201.         return repeats;
  202.     }
  203.  
  204.     /** Sets whether the Timer coalesces multiple pending ActionEvent firings.
  205.       * A busy application may not be able
  206.       * to keep up with a Timer's message generation, causing multiple
  207.       * <b>actionPerformed()</b> message sends to be queued.  When processed,
  208.       * the application sends these messages one after the other, causing the
  209.       * Timer's listeners to receive a sequence of <b>actionPerformed()</b>
  210.       * messages with no delay between them. Coalescing avoids this situation
  211.       * by reducing multiple pending messages to a single message send. Timers
  212.       * coalesce their message sends by default.
  213.       */
  214.     public void setCoalesce(boolean flag) {
  215.         coalesce = flag;
  216.     }
  217.  
  218.     /** Returns <b>true</b> if the Timer coalesces multiple pending
  219.       * <b>performCommand()</b> messages.
  220.       * @see #setCoalesce
  221.       */
  222.     public boolean isCoalesce() {
  223.         return coalesce;
  224.     }
  225.  
  226.     /** Starts the Timer, causing it to send <b>actionPerformed()</b> messages
  227.       * to its listeners.
  228.       * @see #stop
  229.       */
  230.     public void start() {
  231.         timerQueue().addTimer(this,
  232.                               System.currentTimeMillis() + getInitialDelay());
  233.     }
  234.  
  235.     /** Returns <b>true</b> if the Timer is running.
  236.       * @see #start
  237.       */
  238.     public boolean isRunning() {
  239.         return timerQueue().containsTimer(this);
  240.     }
  241.  
  242.     /** Stops a Timer, causing it to stop sending <b>actionPerformed()</b>
  243.       * messages to its Target.
  244.       * @see #start
  245.       */
  246.     public void stop() {
  247.         timerQueue().removeTimer(this);
  248.         cancelEvent();
  249.     }
  250.  
  251.     /**
  252.      * Restarts a Timer, canceling any pending firings, and causing
  253.      * it to fire with its initial dely.
  254.      */
  255.     public void restart() {
  256.         stop();
  257.         start();
  258.     }
  259.  
  260.     synchronized void cancelEvent() {
  261.         if (queuedEvent != null) {
  262.             queuedEvent.setIsCanceled(true);
  263.             queuedEvent = null;
  264.         }
  265.     }
  266.  
  267.     synchronized void post() {
  268.         if (!coalesce || queuedEvent == null) {
  269.             queuedEvent = new TimerEvent(dummyComponent, TIMER_ID);
  270.             Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(queuedEvent);
  271.         }
  272.     }
  273.  
  274.     // Running as untrusted code -- so fire ActionEvent directly instead of via 
  275.     // EventQueue.
  276.     void fire() {
  277.       boolean shouldFire = false;
  278.       DummyComponent c = null;
  279.       TimerEvent e = null;
  280.       synchronized(this) {
  281.         if (!coalesce || queuedEvent == null) {
  282.       e = new TimerEvent(dummyComponent, TIMER_ID);
  283.       c = dummyComponent;
  284.       shouldFire = true;
  285.     }
  286.       }
  287.  
  288.       if(shouldFire) {
  289.     c.fireEvent(e);
  290.       }
  291.     }
  292.  
  293.  
  294.     class DummyComponent extends Component {
  295.         DummyComponent() {
  296.             super();
  297.             enableEvents(TIMER_ID);
  298.         }
  299.  
  300.         protected void processEvent(AWTEvent event) {
  301.             if (event instanceof TimerEvent) {
  302.                 TimerEvent timerEvent = (TimerEvent)event;
  303.                 timerEvent.haveBeenDequeued();
  304.  
  305.                 if (logTimers) {
  306.                     System.out.println("Timer ringing: " + Timer.this + (timerEvent.isCanceled ? " <canceled>" : ""));
  307.                 }
  308.                 if (!timerEvent.isCanceled) {
  309.                     fireActionPerformed(new ActionEvent(Timer.this, 0, null));
  310.                 }
  311.             }
  312.         }
  313.  
  314.         void fireEvent(AWTEvent event) {
  315.             processEvent(event);
  316.         }
  317.     }
  318.  
  319.     class TimerEvent extends AWTEvent {
  320.         boolean isCanceled = false;
  321.  
  322.         TimerEvent(Object target, int id) {
  323.             super(target, id);
  324.         }
  325.  
  326.         synchronized boolean isCanceled() {
  327.             return isCanceled;
  328.         }
  329.  
  330.         synchronized void setIsCanceled(boolean flag) {
  331.             isCanceled = flag;
  332.         }
  333.  
  334.         void haveBeenDequeued() {
  335.             synchronized (Timer.this) {
  336.                 queuedEvent = null;
  337.             }
  338.         }
  339.     }
  340. }
  341.