001    /**
002     * A Stopwatch models a countdown timer that can be turned on and off. It is
003     * also a task that can be scheduled using a java.util.Timer to notify a
004     * StopwatchListener of its decreasing time at regular intervals.
005     */
006    
007    package ui;
008    
009    import java.util.*;
010    import javax.swing.event.EventListenerList;
011    
012    public class Stopwatch extends TimerTask {
013    
014            private boolean running = false;
015    
016            private long millisLeft;
017    
018            private long startTime;
019    
020            /** @requires millisLeft >= 0 */
021            public Stopwatch(long millisLeft) {
022                    this.millisLeft = millisLeft;
023            }
024    
025            /**
026             * Starts the timer, if it was not already running.
027             */
028            public void start() {
029                    if (running) return;
030                    running = true;
031                    startTime = System.currentTimeMillis();
032            }
033    
034            /**
035             * Stops the timer, if it was not already stopped.
036             */
037            public void stop() {
038                    if (!running) return;
039                    running = false;
040                    long stopTime = System.currentTimeMillis();
041                    millisLeft -= (stopTime - startTime);
042            }
043    
044            /**
045             * Returns the amount of time left on the Stopwatch (or zero, if that time
046             * is less than zero).
047             */
048            public long getTime() {
049                    if (running) {
050                            return Math.max((millisLeft - (System.currentTimeMillis() - startTime)),
051                                            0);
052                    } else {
053                            return Math.max(millisLeft, 0);
054                    }
055            }
056    
057            private EventListenerList listenerList = new EventListenerList();
058    
059            /**
060             * Adds a StopwatchListener to this. The listener's timeChanged method will
061             * fire everytime this is run as a TimerTask.
062             */
063            public void addStopwatchListener(StopwatchListener s) {
064                    listenerList.add(StopwatchListener.class, s);
065            }
066    
067            /**
068             * Removes a StopwatchListener from this
069             */
070            public void removeStopwatchListener(StopwatchListener s) {
071                    listenerList.remove(StopwatchListener.class, s);
072            }
073    
074            /**
075             * Informs all of this Stopwatch's listeners that its time is decreasing
076             */
077            protected void fireTimeChanged() {
078                    // Guaranteed to return a non-null array
079                    StopwatchListener[] listeners =
080                            listenerList.getListeners(StopwatchListener.class);
081                    // Process the listeners last to first, notifying
082                    // those that are interested in this event
083                    long time = getTime();
084                    for (int i = listeners.length - 1; i >= 0; i --) {
085                            listeners[i].timeChanged(time, this);
086                    }
087            }
088    
089            /**
090             * Informs all of this Stopwatch's listeners that its time is decreasing
091             */
092            public void run() {
093                    fireTimeChanged();
094            }
095    
096    }