home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / Timer.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  9.6 KB  |  307 lines  |  [TEXT/CWIE]

  1. // Timer.java
  2. // By Ned Etcode
  3. // Copyright 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. /** Object subclass that causes an action to occur at a predefined rate.  For
  10.   * example, an animation object can use a Timer as the trigger for drawing its
  11.   * next frame.  Each Timer has a Target that receives a
  12.   * <b>performCommand()</b> message; the command the Timer sends to its Target;
  13.   * and a delay (the time between <b>performCommand()</b> calls).  When
  14.   * delay milliseconds have passed, a Timer sends the <b>performCommand()</b>
  15.   * message to its Target, passing as parameters the command and the object set
  16.   * using the Timer's <b>setData()</b> method.  This cycle repeats until
  17.   * <b>stop()</b> is called, or halts immediately if the Timer is configured
  18.   * to send its message just once.<p>
  19.   * Using a Timer involves first creating it, then starting it using
  20.   * the <b>start()</b> method.
  21.   * @see Target
  22.   * @note 1.0 changes to detect and stop dealocking better
  23.   * @note 1.0 calling setDelay() on already running Timer works correctly
  24.   * @note 1.1 Timer will get the TimerQueue from the most proper application
  25.   */
  26. public class Timer extends Object implements EventProcessor, EventFilter {
  27.     EventLoop   eventLoop;
  28.     Target      target;
  29.     String      command;
  30.     Object      data;
  31.     long        timeStamp;
  32.     int         initialDelay, delay;
  33.     boolean     repeats = true, coalesce = true, removeEvents;
  34.  
  35.     // These fields are maintained by TimerQueue.
  36.  
  37.     long expirationTime;
  38.     Timer nextTimer;
  39.     boolean running;
  40.  
  41.     /** Constructs a Timer associated with the EventLoop <b>eventLoop</b> that
  42.       * sends <b>performCommand()</b> to <b>target</b> every <b>delay</b>
  43.       * milliseconds.  You only call this constructor if you need to associate
  44.       * a Timer with an EventLoop other than the application's EventLoop.
  45.       * @see Timer(Target, String, int)
  46.       */
  47.     public Timer(EventLoop eventLoop, Target target, String command,
  48.                  int delay) {
  49.         if (eventLoop == null) {
  50.             throw new InconsistencyException("eventLoop parameter is null");
  51.         }
  52.         this.eventLoop = eventLoop;
  53.         this.target = target;
  54.         this.command = command;
  55.         setDelay(delay);
  56.         setInitialDelay(delay);
  57.     }
  58.  
  59.     /** Constructs a Timer associated with the application's EventLoop that
  60.       * sends <b>performCommand()</b> to <b>target</b> every <b>delay</b>
  61.       * milliseconds.
  62.       */
  63.     public Timer(Target target, String command, int delay) {
  64.         this(Application.application().eventLoop(), target, command, delay);
  65.     }
  66.  
  67.     /** Returns the timer queue. */
  68.     TimerQueue timerQueue() {
  69.         if(eventLoop != null && eventLoop.application != null)
  70.             return eventLoop.application.timerQueue();
  71.         return Application.application().timerQueue();
  72.     }
  73.  
  74.     /** Returns the EventLoop associated with this Timer.
  75.       */
  76.     public EventLoop eventLoop() {
  77.         return eventLoop;
  78.     }
  79.  
  80.     /** Sets the Target that will receive <b>performCommand()</b> messages
  81.       * from the Timer.
  82.       */
  83.     public void setTarget(Target target) {
  84.         this.target = target;
  85.     }
  86.  
  87.     /** Returns the Target that will receive <b>performCommand()</b>
  88.       * messages from the Timer.
  89.       * @see #setTarget
  90.       */
  91.     public Target target() {
  92.         return target;
  93.     }
  94.  
  95.     /** Sets the command the Timer sends to its target in the
  96.       * <b>performCommand()</b> method.
  97.       * @see #setTarget
  98.       */
  99.     public void setCommand(String command) {
  100.         this.command = command;
  101.     }
  102.  
  103.     /** Returns the command the Timer sends to its target in the
  104.       * <b>performCommand()</b> message.
  105.       * @see #setCommand
  106.       */
  107.     public String command() {
  108.         return command;
  109.     }
  110.  
  111.     /** Sets the data sent with the command in the <b>performCommand()</b>
  112.       * message to its target.
  113.       */
  114.     public void setData(Object data) {
  115.         this.data = data;
  116.     }
  117.  
  118.     /** Returns the data sent with the command in the <b>performCommand()</b>
  119.       * message to its target.
  120.       * @see #setData
  121.       */
  122.     public Object data() {
  123.         return data;
  124.     }
  125.  
  126.     /** Sets the Timer's delay, the number of milliseconds between successive
  127.       * <b>performCommand()</b> messages to its Target.
  128.       * @see #setTarget
  129.       * @see #setInitialDelay
  130.       */
  131.     public void setDelay(int delay) {
  132.         TimerQueue        queue;
  133.  
  134.         if (delay < 0) {
  135.             throw new InconsistencyException(
  136.                                             "Invalid initial delay: " + delay);
  137.         }
  138.         this.delay = delay;
  139.  
  140.         if (isRunning()) {
  141.             queue = timerQueue();
  142.             queue.removeTimer(this);
  143.             removeEvents();
  144.             queue.addTimer(this, System.currentTimeMillis() + delay);
  145.         }
  146.     }
  147.  
  148.     /** Returns the Timer's delay.
  149.       * @see #setDelay
  150.       */
  151.     public int delay() {
  152.         return delay;
  153.     }
  154.  
  155.     /** Sets the Timer's initial delay.  This is the number of milliseconds
  156.       * the Timer will wait before sending its first <b>performCommand()</b>
  157.       * message to its Target.  This setting has no effect if the Timer is
  158.       * already running.
  159.       * @see #setTarget
  160.       * @see #setDelay
  161.       */
  162.     public void setInitialDelay(int initialDelay) {
  163.         if (initialDelay < 0) {
  164.             throw new InconsistencyException("Invalid initial delay: " +
  165.                                           initialDelay);
  166.         }
  167.         this.initialDelay = initialDelay;
  168.     }
  169.  
  170.     /** Returns the Timer's initial delay.
  171.       * @see #setDelay
  172.       */
  173.     public int initialDelay() {
  174.         return initialDelay;
  175.     }
  176.  
  177.     /** If <b>flag</b> is <b>false</b>, instructs the Timer to send a
  178.       * <b>performCommand()</b> message to its Target only once, and then stop.
  179.       */
  180.     public void setRepeats(boolean flag) {
  181.         repeats = flag;
  182.     }
  183.  
  184.     /** Returns <b>true</b> if the Timer will send a <b>performCommand()</b>
  185.       * message to its target multiple times.
  186.       * @see #setRepeats
  187.       */
  188.     public boolean repeats() {
  189.         return repeats;
  190.     }
  191.  
  192.     /** Returns the time stamp, in milliseconds, associated with the Timer's
  193.       * most recent message to its Target.
  194.       */
  195.     public long timeStamp() {
  196.         return timeStamp;
  197.     }
  198.  
  199.     /** Sets whether the Timer coalesces multiple pending
  200.       * <b>performCommand()</b> messages.  A busy application may not be able
  201.       * to keep up with a Timer's message generation, causing multiple
  202.       * <b>performCommand()</b> message sends to be queued.  When processed,
  203.       * the application sends these messages one after the other, causing the
  204.       * Timer's Target to receive a sequence of <b>performCommand()</b>
  205.       * messages with no delay between them. Coalescing avoids this situation
  206.       * by reducing multiple pending messages to a single message send. Timers
  207.       * coalesce their message sends by default.
  208.       */
  209.     public void setCoalesce(boolean flag) {
  210.         coalesce = flag;
  211.     }
  212.  
  213.     /** Returns <b>true</b> if the Timer coalesces multiple pending
  214.       * <b>performCommand()</b> messages.
  215.       * @see #setCoalesce
  216.       */
  217.     public boolean doesCoalesce() {
  218.         return coalesce;
  219.     }
  220.  
  221.     /** Starts the Timer, causing it to send <b>performCommand()</b> messages
  222.       * to its Target.
  223.       * @see #stop
  224.       */
  225.     public void start() {
  226.         timerQueue().addTimer(this,
  227.                               System.currentTimeMillis() + initialDelay());
  228.     }
  229.  
  230.     /** Returns <b>true</b> if the Timer is running.
  231.       * @see #start
  232.       */
  233.     public boolean isRunning() {
  234.         return timerQueue().containsTimer(this);
  235.     }
  236.  
  237.     /** Stops a Timer, causing it to stop sending <b>performCommand()</b>
  238.       * messages to its Target.
  239.       * @see #start
  240.       */
  241.     public void stop() {
  242.         timerQueue().removeTimer(this);
  243.         removeEvents();
  244.     }
  245.  
  246.     synchronized void removeEvents() {
  247.         removeEvents = true;
  248.         eventLoop.filterEvents(this);
  249.     }
  250.  
  251.     synchronized boolean peekEvent() {
  252.         removeEvents = false;
  253.         return (eventLoop.filterEvents(this) != null);
  254.     }
  255.  
  256.     /** EventFilter interface method, implemented to perform coalescing.  You
  257.       * never call this method.
  258.       * @see #setCoalesce
  259.       */
  260.     public Object filterEvents(Vector events) {
  261.         int count = events.count();
  262.  
  263.         while (count-- > 0) {
  264.             Event event = (Event)events.elementAt(count);
  265.  
  266.             if (event.processor() == this) {
  267.                 if (removeEvents) {
  268.                     events.removeElementAt(count);
  269.                 } else {
  270.                     return event;
  271.                 }
  272.             }
  273.         }
  274.         return null;
  275.     }
  276.  
  277.     /** EventProcessor interface method implemented to perform the Timer's
  278.       * event processing behavior, which is to send the <b>performCommand()</b>
  279.       * message to its Target.  You never call this method.
  280.       * @see EventProcessor
  281.       */
  282.     public void processEvent(Event event) {
  283.         timeStamp = event.timeStamp;
  284.         if (target != null) {
  285.             target.performCommand(command, data);
  286.         }
  287.     }
  288.  
  289.     /** Returns the Timer's string representation.
  290.       */
  291.     public String toString() {
  292.         return "Timer {target = " + target + "; command = " + command +
  293.                "; delay = " + delay + "; initialDelay = " + initialDelay +
  294.                "; repeats = " + repeats + "}";
  295.     }
  296.  
  297.     void post(long timeStamp) {
  298.         Event      newEvent;
  299.  
  300.         if (!coalesce || !peekEvent()) {
  301.             newEvent = new Event(timeStamp);
  302.             newEvent.setProcessor(this);
  303.             eventLoop.addEvent(newEvent);
  304.         }
  305.     }
  306. }
  307.