1. /*
  2. * @(#)Timer.java 1.29 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.util.*;
  9. import java.awt.*;
  10. import java.awt.event.*;
  11. import java.io.Serializable;
  12. import javax.swing.event.EventListenerList;
  13. /**
  14. * Object subclass that causes an action to occur at a predefined rate. For
  15. * example, an animation object can use a Timer as the trigger for drawing its
  16. * next frame. Each Timer has a list of ActionListeners and a delay (
  17. * the time between <b>actionPerfomed()</b> calls). When
  18. * delay milliseconds have passed, a Timer sends the <b>actionPerformed()</b>
  19. * message to its listeners. This cycle repeats until
  20. * <b>stop()</b> is called, or halts immediately if the Jimer is configured
  21. * to send its message just once.<p>
  22. * Using a Timer involves first creating it, then starting it using
  23. * the <b>start()</b> method.
  24. * <p>
  25. * <strong>Warning:</strong>
  26. * Serialized objects of this class will not be compatible with
  27. * future Swing releases. The current serialization support is appropriate
  28. * for short term storage or RMI between applications running the same
  29. * version of Swing. A future release of Swing will provide support for
  30. * long term persistence.
  31. *
  32. * @version 1.29 11/29/01
  33. * @author Dave Moore
  34. */
  35. public class Timer implements Serializable
  36. {
  37. protected EventListenerList listenerList = new EventListenerList();
  38. boolean eventQueued = false;
  39. int initialDelay, delay;
  40. boolean repeats = true, coalesce = true;
  41. Runnable doPostEvent = null;
  42. private static boolean logTimers;
  43. // These fields are maintained by TimerQueue.
  44. // eventQueued can also be reset by the TimerQueue, but will only ever
  45. // happen in applet case when TimerQueues thread is destroyed.
  46. long expirationTime;
  47. Timer nextTimer;
  48. boolean running;
  49. /**
  50. * Creates a Timer that will notify its listeners every
  51. * <i>delay</i> milliseconds.
  52. * @param delay The number of milliseconds between listener notification
  53. * @param listener An initial listener
  54. * @see #setInitialDelay
  55. * @see #setRepeats
  56. */
  57. public Timer(int delay, ActionListener listener) {
  58. super();
  59. this.delay = delay;
  60. this.initialDelay = delay;
  61. doPostEvent = new DoPostEvent();
  62. if (listener != null) {
  63. addActionListener(listener);
  64. }
  65. }
  66. /**
  67. * DoPostEvent is a runnable class that fires actionEvents to
  68. * the listeners on the EventDispatchThread, via invokeLater.
  69. * @see #post
  70. */
  71. class DoPostEvent implements Runnable, Serializable
  72. {
  73. public void run() {
  74. if (logTimers) {
  75. System.out.println("Timer ringing: " + Timer.this);
  76. }
  77. if(eventQueued) {
  78. fireActionPerformed(new ActionEvent(Timer.this, 0, null));
  79. cancelEvent();
  80. }
  81. }
  82. Timer getTimer() {
  83. return Timer.this;
  84. }
  85. }
  86. /**
  87. * Adds an actionListener to the Timer
  88. */
  89. public void addActionListener(ActionListener listener) {
  90. listenerList.add(ActionListener.class, listener);
  91. }
  92. /**
  93. * Removes an ActionListener from the Timer.
  94. */
  95. public void removeActionListener(ActionListener listener) {
  96. listenerList.remove(ActionListener.class, listener);
  97. }
  98. /**
  99. * Notify all listeners that have registered interest for
  100. * notification on this event type. The event instance
  101. * is lazily created using the parameters passed into
  102. * the fire method.
  103. * @see EventListenerList
  104. */
  105. protected void fireActionPerformed(ActionEvent e) {
  106. // Guaranteed to return a non-null array
  107. Object[] listeners = listenerList.getListenerList();
  108. // Process the listeners last to first, notifying
  109. // those that are interested in this event
  110. for (int i=listeners.length-2; i>=0; i-=2) {
  111. if (listeners[i]==ActionListener.class) {
  112. ((ActionListener)listeners[i+1]).actionPerformed(e);
  113. }
  114. }
  115. }
  116. /**
  117. * Returns the timer queue.
  118. */
  119. TimerQueue timerQueue() {
  120. return TimerQueue.sharedInstance();
  121. }
  122. /**
  123. * Enables or disables the timer log. When enabled, a message
  124. * is posted to System.out whenever the timer goes off.
  125. *
  126. * @param flag true to enable logging
  127. * @see #getLogTimers
  128. */
  129. public static void setLogTimers(boolean flag) {
  130. logTimers = flag;
  131. }
  132. /**
  133. * Returns true if logging is enabled.
  134. *
  135. * @return true if logging is enabled
  136. * @see #setLogTimers
  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. if (delay < 0) {
  148. throw new IllegalArgumentException("Invalid delay: " + delay);
  149. }
  150. else {
  151. this.delay = delay;
  152. }
  153. }
  154. /** Returns the Timer's delay.
  155. * @see #setDelay
  156. */
  157. public int getDelay() {
  158. return delay;
  159. }
  160. /**
  161. * Sets the Timer's initial delay. This will be used for the first
  162. * "ringing" of the Timer only. Subsequent ringings will be spaced
  163. * using the delay property.
  164. * @see #setDelay
  165. */
  166. public void setInitialDelay(int initialDelay) {
  167. if (initialDelay < 0) {
  168. throw new IllegalArgumentException("Invalid initial delay: " +
  169. initialDelay);
  170. }
  171. else {
  172. this.initialDelay = initialDelay;
  173. }
  174. }
  175. /**
  176. * Returns the Timer's initial delay.
  177. * @see #setDelay
  178. */
  179. public int getInitialDelay() {
  180. return initialDelay;
  181. }
  182. /**
  183. * If <b>flag</b> is <b>false</b>, instructs the Timer to send
  184. * <b>actionPerformed()</b> to its listeners only once, and then stop.
  185. */
  186. public void setRepeats(boolean flag) {
  187. repeats = flag;
  188. }
  189. /**
  190. * Returns <b>true</b> if the Timer will send a <b>actionPerformed()</b>
  191. * message to its listeners multiple times.
  192. * @see #setRepeats
  193. */
  194. public boolean isRepeats() {
  195. return repeats;
  196. }
  197. /**
  198. * Sets whether the Timer coalesces multiple pending ActionEvent firings.
  199. * A busy application may not be able
  200. * to keep up with a Timer's message generation, causing multiple
  201. * <b>actionPerformed()</b> message sends to be queued. When processed,
  202. * the application sends these messages one after the other, causing the
  203. * Timer's listeners to receive a sequence of <b>actionPerformed()</b>
  204. * messages with no delay between them. Coalescing avoids this situation
  205. * by reducing multiple pending messages to a single message send. Timers
  206. * coalesce their message sends by default.
  207. */
  208. public void setCoalesce(boolean flag) {
  209. coalesce = flag;
  210. }
  211. /**
  212. * Returns <b>true</b> if the Timer coalesces multiple pending
  213. * <b>performCommand()</b> messages.
  214. * @see #setCoalesce
  215. */
  216. public boolean isCoalesce() {
  217. return coalesce;
  218. }
  219. /**
  220. * Starts the Timer, causing it to send <b>actionPerformed()</b> messages
  221. * to its listeners.
  222. * @see #stop
  223. */
  224. public void start() {
  225. timerQueue().addTimer(this,
  226. System.currentTimeMillis() + getInitialDelay());
  227. }
  228. /**
  229. * Returns <b>true</b> if the Timer is running.
  230. * @see #start
  231. */
  232. public boolean isRunning() {
  233. return timerQueue().containsTimer(this);
  234. }
  235. /**
  236. * Stops a Timer, causing it to stop sending <b>actionPerformed()</b>
  237. * messages to its Target.
  238. * @see #start
  239. */
  240. public void stop() {
  241. timerQueue().removeTimer(this);
  242. cancelEvent();
  243. }
  244. /**
  245. * Restarts a Timer, canceling any pending firings, and causing
  246. * it to fire with its initial dely.
  247. */
  248. public void restart() {
  249. stop();
  250. start();
  251. }
  252. synchronized void cancelEvent() {
  253. eventQueued = false;
  254. }
  255. synchronized void post() {
  256. if (eventQueued == false) {
  257. eventQueued = true;
  258. SwingUtilities.invokeLater(doPostEvent);
  259. }
  260. }
  261. }