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