net.sf.fmj.ejmf.toolkit.util.SourcedTimer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fmj Show documentation
Show all versions of fmj Show documentation
Freedom for Media in Java
package net.sf.fmj.ejmf.toolkit.util;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* The SourcedTimer class implements a timer dependent on a named source. This
* is a generalization of a timer simply dependent on a monotonically increasing
* clock.
*
* An instance of SourcedTimer creates a java.swing.Timer and becomes a listener
* on that timer. This timer is called the base timer. Every time the base timer
* fires, the SourcedTimer object asks its source what time it is and then
* notifies its listeners.
*
* This class is used by the TimerPlayer to track media time.
*
* From the book: Essential JMF, Gordon, Talley (ISBN 0130801046). Used with
* permission.
*
* see java.awt.swing.Timer see ejmf.toolkit.TimeSource see
* ejmf.examples.timerplayer.TimerPlayer
*
* @version 1.0
* @author Rob Gordon & Steve Talley
*/
public class SourcedTimer implements ActionListener
{
/**
* How often in milliseconds the baseTimer triggers
*/
protected static int _defaultGran = 1000;
/**
* The source from which the SourcedTimer gets its idea of time
*/
private TimeSource source;
/**
* The base timer
*/
private Timer baseTimer;
/**
* These are listeners on the SourcedTimer
*/
private EventListenerList listenerList = null;
/**
* This event is sent to all of my listeners
*/
private SourcedTimerEvent event;
/**
* Flag that tracks whether base timer is running.
*/
private boolean started = false;
// This needs to be global since it is used by inner class
private Object[] listeners;
/**
* Create a SourcedTimer for the given source using default granularity.
*
* @param src
* An object that implements the TimeSource interface.
*/
public SourcedTimer(TimeSource src)
{
this(src, _defaultGran);
}
/**
* Create a SourcedTimer for the given source with the specified
* granularity.
*
* @param src
* An object that implements the TimeSource interface.
* @param granularity
* Periood in milliseconds that base timer should fire.
*/
public SourcedTimer(TimeSource src, int granularity)
{
source = src;
event = new SourcedTimerEvent(this, 0);
baseTimer = new Timer(granularity, this);
baseTimer.setInitialDelay(0);
}
/**
* Create a SourcedTimer for the given source. Use the Timer passed as an
* argument for the base timer.
*
* @param src
* An object that implements the TimeSource interface.
* @param timer
* A java.swing.Timer object for use as base timer.
*/
public SourcedTimer(TimeSource src, Timer timer)
{
source = src;
event = new SourcedTimerEvent(this, 0);
baseTimer = timer;
}
/**
* Called in response to an ActionEvent from the associated base timer.
* Nominally this method is called every granularity milliseconds.
*
* @param e
* ActionEvent from base timer.
*/
public void actionPerformed(ActionEvent e)
{
runNotifyThread(source.getTime());
}
/**
* Add a listener to this object.
*
* @param l
* An object that implements SourcedTimerListener interface.
*/
public void addSourcedTimerListener(SourcedTimerListener l)
{
if (listenerList == null)
listenerList = new EventListenerList();
listenerList.add(SourcedTimerListener.class, l);
}
/**
* A client of SourcedTimer may need to convert source timer time from raw
* units to some other units for display purposes. This method is available
* to listeners who have a reference to a SourcedTimer but not necessarily
* the source itself. It simply delegates to the source and asks what number
* are raw units divider by to arrive at seconds.
*
*
* @return A number used to divide base timer time for conversion to
* seconds.
*/
public long getConversionDivisor()
{
return source.getConversionDivisor();
}
/**
* Starts a thread that is responsible for notifying any listeners on this
* SourcedTimer. For each listener, its timerUpdate method is called.
*
* @param nsecs
* Time in nanoseconds from base timer.
*/
private void runNotifyThread(long nsecs)
{
event.setTime(nsecs);
listeners = listenerList.getListenerList();
Thread nThread = new Thread("SourcedTimer Notify Thread")
{
@Override
public void run()
{
// This is canonical means for traversing a
// Listener list, notifying listeners
for (int i = listeners.length - 2; i >= 0; i -= 2)
if (listeners[i] == SourcedTimerListener.class)
((SourcedTimerListener) listeners[i + 1])
.timerUpdate(event);
}
};
nThread.start();
}
/**
* Start the timer. The associated base timer is started if it is not
* already running.
*
*/
public void start()
{
if (started == false)
{
baseTimer.start();
runNotifyThread(0);
}
}
/**
* Stop the timer. The associated base timer is stopped.
*
*/
public void stop()
{
started = false;
baseTimer.stop();
// Force one last notification. This call acts
// like a 'flush' event and ensues a final event
// occurs when stopping Timer. We do it after stop
// in case it takes a while.
runNotifyThread(source.getTime());
}
}