1. /*
  2. * @(#)Timer.java 1.43 03/01/23
  3. *
  4. * Copyright 2003 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. * Fires one or more action events after a specified delay.
  15. * For example, an animation object can use a <code>Timer</code>
  16. * as the trigger for drawing its frames.
  17. *
  18. *<p>
  19. *
  20. * Setting up a timer
  21. * involves creating a <code>Timer</code> object,
  22. * registering one or more action listeners on it,
  23. * and starting the timer using
  24. * the <code>start</code> method.
  25. * For example,
  26. * the following code creates and starts a timer
  27. * that fires an action event once per second
  28. * (as specified by the first argument to the <code>Timer</code> constructor).
  29. * The second argument to the <code>Timer</code> constructor
  30. * specifies a listener to receive the timer's action events.
  31. *
  32. *<pre>
  33. * int delay = 1000; //milliseconds
  34. * ActionListener taskPerformer = new ActionListener() {
  35. * public void actionPerformed(ActionEvent evt) {
  36. * <em>//...Perform a task...</em>
  37. * }
  38. * };
  39. * new Timer(delay, taskPerformer).start();</pre>
  40. *
  41. * <p>
  42. * Each <code>Timer</code>
  43. * has one or more action listeners
  44. * and a <em>delay</em>
  45. * (the time between action events).
  46. * When
  47. * <em>delay</em> milliseconds have passed, the <code>Timer</code>
  48. * fires an action event to its listeners.
  49. * By default, this cycle repeats until
  50. * the <code>stop</code> method is called.
  51. * If you want the timer to fire only once,
  52. * invoke <code>setRepeats(false)</code> on the timer.
  53. * To make the delay before the first action event
  54. * different from the delay between events,
  55. * use the <code>setInitialDelay</code> method.
  56. *
  57. * <p>
  58. * Although all <code>Timer</code>s perform their waiting
  59. * using a single, shared thread
  60. * (created by the first <code>Timer</code> object that executes),
  61. * the action event handlers for <code>Timer</code>s
  62. * execute on another thread -- the event-dispatching thread.
  63. * This means that the action handlers for <code>Timer</code>s
  64. * can safely perform operations on Swing components.
  65. * However, it also means that the handlers must execute quickly
  66. * to keep the GUI responsive.
  67. *
  68. * <p>
  69. * In v 1.3, another <code>Timer</code> class was added
  70. * to the Java platform: <code>java.util.Timer</code>.
  71. * Both it and <code>javax.swing.Timer</code>
  72. * provide the same basic functionality,
  73. * but <code>java.util.Timer</code>
  74. * is more general and has more features.
  75. * The <code>javax.swing.Timer</code> has two features
  76. * that can make it a little easier to use with GUIs.
  77. * First, its event handling metaphor is familiar to GUI programmers
  78. * and can make dealing with the event-dispatching thread
  79. * a bit simpler.
  80. * Second, its
  81. * automatic thread sharing means that you don't have to
  82. * take special steps to avoid spawning
  83. * too many threads.
  84. * Instead, your timer uses the same thread
  85. * used to make cursors blink,
  86. * tool tips appear,
  87. * and so on.
  88. *
  89. * <p>
  90. * You can find further documentation
  91. * and several examples of using timers by visiting
  92. * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html"
  93. * target = "_top">How to Use Timers</a>,
  94. * a section in <em>The Java Tutorial.</em>
  95. * For more examples and help in choosing between
  96. * this <code>Timer</code> class and
  97. * <code>java.util.Timer</code>,
  98. * see
  99. * <a href="http://java.sun.com/products/jfc/tsc/articles/timer/"
  100. * target="_top">Using Timers in Swing Applications</a>,
  101. * an article in <em>The Swing Connection.</em>
  102. * <p>
  103. * <strong>Warning:</strong>
  104. * Serialized objects of this class will not be compatible with
  105. * future Swing releases. The current serialization support is
  106. * appropriate for short term storage or RMI between applications running
  107. * the same version of Swing. As of 1.4, support for long term storage
  108. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  109. * has been added to the <code>java.beans</code> package.
  110. * Please see {@link java.beans.XMLEncoder}.
  111. *
  112. * @see java.util.Timer <code>java.util.Timer</code>
  113. *
  114. *
  115. * @version 1.43 01/23/03
  116. * @author Dave Moore
  117. */
  118. public class Timer implements Serializable
  119. {
  120. protected EventListenerList listenerList = new EventListenerList();
  121. // The following field strives to maintain the following:
  122. // If coalesce is true, only allow one Runnable to be queued on the
  123. // EventQueue and be pending (ie in the process of notifying the
  124. // ActionListener). If we didn't do this it would allow for a
  125. // situation where the app is taking too long to process the
  126. // actionPerformed, and thus we'ld end up queing a bunch of Runnables
  127. // and the app would never return: not good. This of course implies
  128. // you can get dropped events, but such is life.
  129. // notify is used to indicate if the ActionListener can be notified, when
  130. // the Runnable is processed if this is true it will notify the listeners.
  131. // notify is set to true when the Timer fires and the Runnable is queued.
  132. // It will be set to false after notifying the listeners (if coalesce is
  133. // true) or if the developer invokes stop.
  134. private boolean notify = false;
  135. int initialDelay, delay;
  136. boolean repeats = true, coalesce = true;
  137. Runnable doPostEvent = null;
  138. private static boolean logTimers;
  139. // These fields are maintained by TimerQueue.
  140. // eventQueued can also be reset by the TimerQueue, but will only ever
  141. // happen in applet case when TimerQueues thread is destroyed.
  142. long expirationTime;
  143. Timer nextTimer;
  144. boolean running;
  145. /**
  146. * Creates a <code>Timer</code> that will notify its listeners every
  147. * <code>delay</code> milliseconds. If <code>delay</code> is less than
  148. * or equal to zero the timer will fire as soon as it
  149. * is started. If <code>listener</code> is not <code>null</code>,
  150. * it's registered as an action listener on the timer.
  151. *
  152. * @param delay the number of milliseconds between action events
  153. * @param listener an initial listener; can be <code>null</code>
  154. *
  155. * @see #addActionListener
  156. * @see #setInitialDelay
  157. * @see #setRepeats
  158. */
  159. public Timer(int delay, ActionListener listener) {
  160. super();
  161. this.delay = delay;
  162. this.initialDelay = delay;
  163. doPostEvent = new DoPostEvent();
  164. if (listener != null) {
  165. addActionListener(listener);
  166. }
  167. }
  168. /**
  169. * DoPostEvent is a runnable class that fires actionEvents to
  170. * the listeners on the EventDispatchThread, via invokeLater.
  171. * @see #post
  172. */
  173. class DoPostEvent implements Runnable, Serializable
  174. {
  175. public void run() {
  176. if (logTimers) {
  177. System.out.println("Timer ringing: " + Timer.this);
  178. }
  179. if(notify) {
  180. fireActionPerformed(new ActionEvent(Timer.this, 0, null,
  181. System.currentTimeMillis(),
  182. 0));
  183. if (coalesce) {
  184. cancelEvent();
  185. }
  186. }
  187. }
  188. Timer getTimer() {
  189. return Timer.this;
  190. }
  191. }
  192. /**
  193. * Adds an action listener to the <code>Timer</code>.
  194. *
  195. * @param listener the listener to add
  196. *
  197. * @see #Timer
  198. */
  199. public void addActionListener(ActionListener listener) {
  200. listenerList.add(ActionListener.class, listener);
  201. }
  202. /**
  203. * Removes the specified action listener from the <code>Timer</code>.
  204. *
  205. * @param listener the listener to remove
  206. */
  207. public void removeActionListener(ActionListener listener) {
  208. listenerList.remove(ActionListener.class, listener);
  209. }
  210. /**
  211. * Returns an array of all the action listeners registered
  212. * on this timer.
  213. *
  214. * @return all of the timer's <code>ActionListener</code>s or an empty
  215. * array if no action listeners are currently registered
  216. *
  217. * @see #addActionListener
  218. * @see #removeActionListener
  219. *
  220. * @since 1.4
  221. */
  222. public ActionListener[] getActionListeners() {
  223. return (ActionListener[])listenerList.getListeners(
  224. ActionListener.class);
  225. }
  226. /**
  227. * Notifies all listeners that have registered interest for
  228. * notification on this event type.
  229. *
  230. * @param e the action event to fire
  231. * @see EventListenerList
  232. */
  233. protected void fireActionPerformed(ActionEvent e) {
  234. // Guaranteed to return a non-null array
  235. Object[] listeners = listenerList.getListenerList();
  236. // Process the listeners last to first, notifying
  237. // those that are interested in this event
  238. for (int i=listeners.length-2; i>=0; i-=2) {
  239. if (listeners[i]==ActionListener.class) {
  240. ((ActionListener)listeners[i+1]).actionPerformed(e);
  241. }
  242. }
  243. }
  244. /**
  245. * Returns an array of all the objects currently registered as
  246. * <code><em>Foo</em>Listener</code>s
  247. * upon this <code>Timer</code>.
  248. * <code><em>Foo</em>Listener</code>s
  249. * are registered using the <code>add<em>Foo</em>Listener</code> method.
  250. * <p>
  251. * You can specify the <code>listenerType</code> argument
  252. * with a class literal, such as <code><em>Foo</em>Listener.class</code>.
  253. * For example, you can query a <code>Timer</code>
  254. * instance <code>t</code>
  255. * for its action listeners
  256. * with the following code:
  257. *
  258. * <pre>ActionListener[] als = (ActionListener[])(t.getListeners(ActionListener.class));</pre>
  259. *
  260. * If no such listeners exist,
  261. * this method returns an empty array.
  262. *
  263. * @param listenerType the type of listeners requested;
  264. * this parameter should specify an interface
  265. * that descends from <code>java.util.EventListener</code>
  266. * @return an array of all objects registered as
  267. * <code><em>Foo</em>Listener</code>s
  268. * on this timer,
  269. * or an empty array if no such
  270. * listeners have been added
  271. * @exception ClassCastException if <code>listenerType</code> doesn't
  272. * specify a class or interface that implements
  273. * <code>java.util.EventListener</code>
  274. *
  275. * @see #getActionListeners
  276. * @see #addActionListener
  277. * @see #removeActionListener
  278. *
  279. * @since 1.3
  280. */
  281. public EventListener[] getListeners(Class listenerType) {
  282. return listenerList.getListeners(listenerType);
  283. }
  284. /**
  285. * Returns the timer queue.
  286. */
  287. TimerQueue timerQueue() {
  288. return TimerQueue.sharedInstance();
  289. }
  290. /**
  291. * Enables or disables the timer log. When enabled, a message
  292. * is posted to <code>System.out</code> whenever the timer goes off.
  293. *
  294. * @param flag <code>true</code> to enable logging
  295. * @see #getLogTimers
  296. */
  297. public static void setLogTimers(boolean flag) {
  298. logTimers = flag;
  299. }
  300. /**
  301. * Returns <code>true</code> if logging is enabled.
  302. *
  303. * @return <code>true</code> if logging is enabled; otherwise, false
  304. * @see #setLogTimers
  305. */
  306. public static boolean getLogTimers() {
  307. return logTimers;
  308. }
  309. /**
  310. * Sets the <code>Timer</code>'s delay, the number of milliseconds
  311. * between successive action events.
  312. *
  313. * @param delay the delay in milliseconds
  314. * @see #setInitialDelay
  315. */
  316. public void setDelay(int delay) {
  317. if (delay < 0) {
  318. throw new IllegalArgumentException("Invalid delay: " + delay);
  319. }
  320. else {
  321. this.delay = delay;
  322. }
  323. }
  324. /**
  325. * Returns the delay, in milliseconds,
  326. * between firings of action events.
  327. *
  328. * @see #setDelay
  329. * @see #getInitialDelay
  330. */
  331. public int getDelay() {
  332. return delay;
  333. }
  334. /**
  335. * Sets the <code>Timer</code>'s initial delay,
  336. * which by default is the same as the between-event delay.
  337. * This is used only for the first action event.
  338. * Subsequent action events are spaced
  339. * using the delay property.
  340. *
  341. * @param initialDelay the delay, in milliseconds,
  342. * between the invocation of the <code>start</code>
  343. * method and the first action event
  344. * fired by this timer
  345. *
  346. * @see #setDelay
  347. */
  348. public void setInitialDelay(int initialDelay) {
  349. if (initialDelay < 0) {
  350. throw new IllegalArgumentException("Invalid initial delay: " +
  351. initialDelay);
  352. }
  353. else {
  354. this.initialDelay = initialDelay;
  355. }
  356. }
  357. /**
  358. * Returns the <code>Timer</code>'s initial delay.
  359. *
  360. * @see #setInitialDelay
  361. * @see #setDelay
  362. */
  363. public int getInitialDelay() {
  364. return initialDelay;
  365. }
  366. /**
  367. * If <code>flag</code> is <code>false</code>,
  368. * instructs the <code>Timer</code> to send only one
  369. * action event to its listeners.
  370. *
  371. * @param flag specify <code>false</code> to make the timer
  372. * stop after sending its first action event
  373. */
  374. public void setRepeats(boolean flag) {
  375. repeats = flag;
  376. }
  377. /**
  378. * Returns <code>true</code> (the default)
  379. * if the <code>Timer</code> will send
  380. * an action event
  381. * to its listeners multiple times.
  382. *
  383. * @see #setRepeats
  384. */
  385. public boolean isRepeats() {
  386. return repeats;
  387. }
  388. /**
  389. * Sets whether the <code>Timer</code> coalesces multiple pending
  390. * <code>ActionEvent</code> firings.
  391. * A busy application may not be able
  392. * to keep up with a <code>Timer</code>'s event generation,
  393. * causing multiple
  394. * action events to be queued. When processed,
  395. * the application sends these events one after the other, causing the
  396. * <code>Timer</code>'s listeners to receive a sequence of
  397. * events with no delay between them. Coalescing avoids this situation
  398. * by reducing multiple pending events to a single event.
  399. * <code>Timer</code>s
  400. * coalesce events by default.
  401. *
  402. * @param flag specify <code>false</code> to turn off coalescing
  403. */
  404. public void setCoalesce(boolean flag) {
  405. boolean old = coalesce;
  406. coalesce = flag;
  407. if (!old && coalesce) {
  408. // We must do this as otherwise if the Timer once notified
  409. // in !coalese mode notify will be stuck to true and never
  410. // become false.
  411. cancelEvent();
  412. }
  413. }
  414. /**
  415. * Returns <code>true</code> if the <code>Timer</code> coalesces
  416. * multiple pending action events.
  417. *
  418. * @see #setCoalesce
  419. */
  420. public boolean isCoalesce() {
  421. return coalesce;
  422. }
  423. /**
  424. * Starts the <code>Timer</code>,
  425. * causing it to start sending action events
  426. * to its listeners.
  427. *
  428. * @see #stop
  429. */
  430. public void start() {
  431. timerQueue().addTimer(this,
  432. System.currentTimeMillis() + getInitialDelay());
  433. }
  434. /**
  435. * Returns <code>true</code> if the <code>Timer</code> is running.
  436. *
  437. * @see #start
  438. */
  439. public boolean isRunning() {
  440. return timerQueue().containsTimer(this);
  441. }
  442. /**
  443. * Stops the <code>Timer</code>,
  444. * causing it to stop sending action events
  445. * to its listeners.
  446. *
  447. * @see #start
  448. */
  449. public void stop() {
  450. timerQueue().removeTimer(this);
  451. cancelEvent();
  452. }
  453. /**
  454. * Restarts the <code>Timer</code>,
  455. * canceling any pending firings and causing
  456. * it to fire with its initial delay.
  457. */
  458. public void restart() {
  459. stop();
  460. start();
  461. }
  462. /**
  463. * Resets the internal state to indicate this Timer shouldn't notify
  464. * any of its listeners. This does not stop a repeatable Timer from
  465. * firing again, use <code>stop</code> for that.
  466. */
  467. synchronized void cancelEvent() {
  468. notify = false;
  469. }
  470. synchronized void post() {
  471. if (notify == false || !coalesce) {
  472. notify = true;
  473. SwingUtilities.invokeLater(doPostEvent);
  474. }
  475. }
  476. }