package ie.dcu.apps.ist.widgets; import ie.dcu.apps.ist.event.*; public class Ticker implements Runnable { private final TickerListener listener; private Thread thread = null; private boolean pause = false; private boolean stop = false; private long napTime = 100; private long interval = 1000; private long elapsed = 0; private long startTime = 0; private long pausedTime = 0; // State variables private boolean paused = false; private boolean stopped = true; public Ticker(TickerListener listener) { // Check listener if (listener == null) { throw new IllegalArgumentException(); } this.listener = listener; } public Ticker(TickerListener listener, long interval) { // Check listener if (listener == null) { throw new IllegalArgumentException(); } // Check interval if (interval < 0) { throw new IllegalArgumentException(); } // Assign this.listener = listener; this.interval = interval; this.napTime = interval / 10; } public synchronized long elapsed() { return elapsed; } public void start() { if (thread != null) { throw new IllegalStateException("Cannot restart threads"); } thread = new Thread(this, "TimerThread"); thread.start(); } public void run() { synchronized (this) { stopped = false; } // Set start time startTime = System.currentTimeMillis(); // Loop while (true) { // Yawn! Z Z z z z Z Z Z z z z Z Z Z ... sleep(napTime); // Wait while thread is paused synchronized (this) { if (pause) { // Remember when pausing started long now = System.currentTimeMillis(); // Set paused flag to true and notify paused = true; notifyAll(); // Wait until woken up while (paused) doWait(); // Add duration we've been paused for pausedTime += System.currentTimeMillis() - now; // Clear pause flag && notify pause = false; notifyAll(); } } // Check for stop flag synchronized (this) { if (stop) { stopped = true; notifyAll(); break; } } // HI-HO-HI-HO ... work(); } } private void work() { boolean event = false; synchronized (this) { // Calculate total elapsed time in milliseconds long now = System.currentTimeMillis(); long elapsed = now - (startTime + pausedTime); // Calculate time elapsed since last event long sinceLast = elapsed - this.elapsed; if (interval <= sinceLast) { // Compensate for any difference long diff = sinceLast - interval; // Its time for another event this.elapsed = elapsed - diff; // Fire event flag event = true; } } // Do event if (event) { synchronized (listener) { listener.tick(new TickerEvent(this, elapsed)); } } } public void pause() { // Pause running thread synchronized (this) { pause = true; // Wait for pause to occur while (!paused) doWait(); } } public void resume() { // Wake up paused threads synchronized (this) { if (paused) { paused = false; notifyAll(); } while (pause) doWait(); } } public boolean isPaused() { synchronized (this) { return paused; } } public void stop() { synchronized (this) { // Resume paused threads if (paused) { paused = false; notifyAll(); } while (pause) doWait(); // Stop stop = true; // Wait until stop block reached while (!stopped) doWait(); } } public void stopLater() { synchronized (this) { // Resume paused threads if (paused) { paused = false; notifyAll(); } while (pause) doWait(); // Stop stop = true; } } public boolean isStopped() { synchronized (this) { return stopped; } } private void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { // Ignore } } private void doWait() { try { wait(); } catch (InterruptedException e) { // ignore } } }