home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 10.5 KB | 341 lines |
- /*
- * @(#)Timer.java 1.17 98/02/02
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- */
-
-
- /**
- * Allows objects to be notified at future intervals, using the
- * ActionListener interface.
- *
- *
- * @version 1.17 02/02/98
- * @author Dave Moore
- */
-
- package java.awt.swing;
-
- import java.util.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.io.Serializable;
- import java.awt.swing.event.EventListenerList;
-
-
- /**
- * Object subclass that causes an action to occur at a predefined rate. For
- * example, an animation object can use a JTimer as the trigger for drawing its
- * next frame. Each Timer has a list of ActionListeners and a delay (
- * the time between <b>actionPerfomed()</b> calls). When
- * delay milliseconds have passed, a JTimer sends the <b>actionPerformed()</b>
- * message to its listeners. This cycle repeats until
- * <b>stop()</b> is called, or halts immediately if the Jimer is configured
- * to send its message just once.<p>
- * Using a JTimer involves first creating it, then starting it using
- * the <b>start()</b> method.
- * <p>
- * Warning: serialized objects of this class will not be compatible with
- * future swing releases. The current serialization support is appropriate
- * for short term storage or RMI between Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- *
- * @version 1.17 02/02/98
- * @author unknown
- */
- public class Timer implements Serializable
- {
- int initialDelay, delay;
- boolean repeats = true, coalesce = true;
- private DummyComponent dummyComponent;
- protected EventListenerList listenerList = new EventListenerList();
- TimerEvent queuedEvent;
- static final int TIMER_ID = AWTEvent.RESERVED_ID_MAX + 1;
- private static boolean logTimers;
-
- // These fields are maintained by TimerQueue.
-
- long expirationTime;
- Timer nextTimer;
- boolean running;
-
- /**
- * Creates a JTimer that will notify its listeners every
- * <i>delay</i> milliseconds.
- * @param delay The number of milliseconds between listener notification
- * @param listener An initial listener
- * @see #setInitialDelay
- * @see #setRepeats
- */
- public Timer(int delay, ActionListener listener) {
- super();
- this.delay = delay;
- this.initialDelay = delay;
- dummyComponent = new DummyComponent();
- if (listener != null) {
- addActionListener(listener);
- }
- }
-
- /**
- * Adds an actionListener to the Timer
- */
- public void addActionListener(ActionListener listener) {
- listenerList.add(ActionListener.class, listener);
- }
-
- /**
- * Removes an ActionListener from the Timer.
- */
- public void removeActionListener(ActionListener listener) {
- listenerList.remove(ActionListener.class, listener);
- }
-
- /*
- * Notify all listeners that have registered interest for
- * notification on this event type. The event instance
- * is lazily created using the parameters passed into
- * the fire method.
- * @see EventListenerList
- */
- protected void fireActionPerformed(ActionEvent e) {
- // Guaranteed to return a non-null array
- Object[] listeners = listenerList.getListenerList();
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length-2; i>=0; i-=2) {
- if (listeners[i]==ActionListener.class) {
- ((ActionListener)listeners[i+1]).actionPerformed(e);
- }
- }
- }
-
- /** Returns the timer queue. */
- TimerQueue timerQueue() {
- return TimerQueue.sharedInstance();
- }
-
- public static void setLogTimers(boolean flag) {
- logTimers = flag;
- }
-
- public static boolean getLogTimers() {
- return logTimers;
- }
-
- /** Sets the Timer's delay, the number of milliseconds between successive
- * <b>actionPerfomed()</b> messages to its listeners
- * @see #setInitialDelay
- */
- public void setDelay(int delay) {
- TimerQueue queue;
-
- if (delay < 0) {
- throw new RuntimeException("Invalid initial delay: " + delay);
- }
- this.delay = delay;
-
- if (isRunning()) {
- queue = timerQueue();
- queue.removeTimer(this);
- cancelEvent();
- queue.addTimer(this, System.currentTimeMillis() + delay);
- }
- }
-
- /** Returns the Timer's delay.
- * @see #setDelay
- */
- public int getDelay() {
- return delay;
- }
-
- /** Sets the Timer's initial delay. This will be used for the first
- * "ringing" of the Timer only. Subsequent ringings will be spaced
- * using the delay property.
- * @see #setDelay
- */
- public void setInitialDelay(int initialDelay) {
- if (initialDelay < 0) {
- throw new RuntimeException("Invalid initial delay: " +
- initialDelay);
- }
- this.initialDelay = initialDelay;
- }
-
- /** Returns the Timer's initial delay.
- * @see #setDelay
- */
- public int getInitialDelay() {
- return initialDelay;
- }
-
- /** If <b>flag</b> is <b>false</b>, instructs the Timer to send
- * <b>actionPerformed()</b> to its listeners only once, and then stop.
- */
- public void setRepeats(boolean flag) {
- repeats = flag;
- }
-
- /** Returns <b>true</b> if the Timer will send a <b>actionPerformed()</b>
- * message to its listeners multiple times.
- * @see #setRepeats
- */
- public boolean isRepeats() {
- return repeats;
- }
-
- /** Sets whether the Timer coalesces multiple pending ActionEvent firings.
- * A busy application may not be able
- * to keep up with a Timer's message generation, causing multiple
- * <b>actionPerformed()</b> message sends to be queued. When processed,
- * the application sends these messages one after the other, causing the
- * Timer's listeners to receive a sequence of <b>actionPerformed()</b>
- * messages with no delay between them. Coalescing avoids this situation
- * by reducing multiple pending messages to a single message send. Timers
- * coalesce their message sends by default.
- */
- public void setCoalesce(boolean flag) {
- coalesce = flag;
- }
-
- /** Returns <b>true</b> if the Timer coalesces multiple pending
- * <b>performCommand()</b> messages.
- * @see #setCoalesce
- */
- public boolean isCoalesce() {
- return coalesce;
- }
-
- /** Starts the Timer, causing it to send <b>actionPerformed()</b> messages
- * to its listeners.
- * @see #stop
- */
- public void start() {
- timerQueue().addTimer(this,
- System.currentTimeMillis() + getInitialDelay());
- }
-
- /** Returns <b>true</b> if the Timer is running.
- * @see #start
- */
- public boolean isRunning() {
- return timerQueue().containsTimer(this);
- }
-
- /** Stops a Timer, causing it to stop sending <b>actionPerformed()</b>
- * messages to its Target.
- * @see #start
- */
- public void stop() {
- timerQueue().removeTimer(this);
- cancelEvent();
- }
-
- /**
- * Restarts a Timer, canceling any pending firings, and causing
- * it to fire with its initial dely.
- */
- public void restart() {
- stop();
- start();
- }
-
- synchronized void cancelEvent() {
- if (queuedEvent != null) {
- queuedEvent.setIsCanceled(true);
- queuedEvent = null;
- }
- }
-
- synchronized void post() {
- if (!coalesce || queuedEvent == null) {
- queuedEvent = new TimerEvent(dummyComponent, TIMER_ID);
- Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(queuedEvent);
- }
- }
-
- // Running as untrusted code -- so fire ActionEvent directly instead of via
- // EventQueue.
- void fire() {
- boolean shouldFire = false;
- DummyComponent c = null;
- TimerEvent e = null;
- synchronized(this) {
- if (!coalesce || queuedEvent == null) {
- e = new TimerEvent(dummyComponent, TIMER_ID);
- c = dummyComponent;
- shouldFire = true;
- }
- }
-
- if(shouldFire) {
- c.fireEvent(e);
- }
- }
-
-
- class DummyComponent extends Component {
- DummyComponent() {
- super();
- enableEvents(TIMER_ID);
- }
-
- protected void processEvent(AWTEvent event) {
- if (event instanceof TimerEvent) {
- TimerEvent timerEvent = (TimerEvent)event;
- timerEvent.haveBeenDequeued();
-
- if (logTimers) {
- System.out.println("Timer ringing: " + Timer.this + (timerEvent.isCanceled ? " <canceled>" : ""));
- }
- if (!timerEvent.isCanceled) {
- fireActionPerformed(new ActionEvent(Timer.this, 0, null));
- }
- }
- }
-
- void fireEvent(AWTEvent event) {
- processEvent(event);
- }
- }
-
- class TimerEvent extends AWTEvent {
- boolean isCanceled = false;
-
- TimerEvent(Object target, int id) {
- super(target, id);
- }
-
- synchronized boolean isCanceled() {
- return isCanceled;
- }
-
- synchronized void setIsCanceled(boolean flag) {
- isCanceled = flag;
- }
-
- void haveBeenDequeued() {
- synchronized (Timer.this) {
- queuedEvent = null;
- }
- }
- }
- }
-