diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java
index 313bf41..ec3a22a 100644
--- a/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java
@@ -62,7 +62,7 @@
import edu.umd.cs.piccolo.util.PStack;
/**
- * PCanvas is a simple Swing component that can be used to embed Piccolo
+ * PSWTCanvas is a simple Swing component that can be used to embed Piccolo
* into a Java Swing application. Canvas's view the Piccolo scene graph through
* a camera. The canvas manages screen updates coming from this camera, and
* forwards swing mouse and keyboard events to the camera.
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
index 9482615..b301193 100644
--- a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
@@ -36,30 +36,28 @@
import org.eclipse.swt.widgets.Display;
/**
+ *
+ *
* @author Lance Good
*/
public class SWTTimer extends Timer {
-
- /**
- *
- */
private static final long serialVersionUID = 1L;
private boolean notify = false;
- int initialDelay, delay;
- boolean repeats = true, coalesce = true;
-
- Runnable doPostEvent = null;
-
- Display display = null;
+ private int initialDelay;
+ private int delay;
+ private boolean repeats = true;
+ private boolean coalesce = true;
+ private Runnable doPostEvent = null;
+ private Display display = null;
// These fields are maintained by TimerQueue.
// eventQueued can also be reset by the TimerQueue, but will only ever
// happen in applet case when TimerQueues thread is destroyed.
- long expirationTime;
- SWTTimer nextTimer;
- boolean running;
+ private long expirationTime;
+ private SWTTimer nextTimer;
+ private boolean running;
/**
* DoPostEvent is a runnable class that fires actionEvents to the listeners
@@ -69,7 +67,6 @@
*/
class SWTDoPostEvent implements Runnable {
public void run() {
-
if (notify) {
fireActionPerformed(new ActionEvent(SWTTimer.this, 0, null, System.currentTimeMillis(), 0));
if (coalesce) {
@@ -86,8 +83,9 @@
/**
* Constructor for SWTTimer.
*
- * @param delay
- * @param listener
+ * @param display display associated with this timer
+ * @param delay time in milliseconds between firings of this timer
+ * @param listener action listener to fire when the timer fires
*/
public SWTTimer(final Display display, final int delay, final ActionListener listener) {
super(delay, listener);
@@ -145,6 +143,7 @@
*
* @see #setDelay
* @see #getInitialDelay
+ * @return delay in milliseconds between firings of this timer
*/
public int getDelay() {
return delay;
@@ -171,10 +170,12 @@
}
/**
- * Returns the Timer
's initial delay.
+ * Returns the Timer
's initial delay. By default this is the
+ * same as the value returned by getDelay.
*
* @see #setInitialDelay
* @see #setDelay
+ * @return the initial delay of this timer
*/
public int getInitialDelay() {
return initialDelay;
@@ -196,6 +197,7 @@
* send an action event to its listeners multiple times.
*
* @see #setRepeats
+ * @return true if this timer should repeat when completed
*/
public boolean isRepeats() {
return repeats;
@@ -229,6 +231,7 @@
* pending action events.
*
* @see #setCoalesce
+ * @return true if this timer coalesces multiple pending action events
*/
public boolean isCoalesce() {
return coalesce;
@@ -248,6 +251,7 @@
* Returns true
if the Timer
is running.
*
* @see #start
+ * @return true if this timer is scheduled to run
*/
public boolean isRunning() {
return timerQueue().containsTimer(this);
@@ -283,10 +287,45 @@
}
synchronized void postOverride() {
- if (notify == false || !coalesce) {
+ if (!notify || !coalesce) {
notify = true;
display.asyncExec(doPostEvent);
}
}
+ /**
+ * @param expirationTime the expirationTime to set
+ */
+ public void setExpirationTime(final long expirationTime) {
+ this.expirationTime = expirationTime;
+ }
+
+ /**
+ * @return the expirationTime
+ */
+ public long getExpirationTime() {
+ return expirationTime;
+ }
+
+ /**
+ * @param nextTimer the nextTimer to set
+ */
+ void setNextTimer(final SWTTimer nextTimer) {
+ this.nextTimer = nextTimer;
+ }
+
+ /**
+ * @return the nextTimer
+ */
+ SWTTimer getNextTimer() {
+ return nextTimer;
+ }
+
+ /**
+ * @param running the running to set
+ */
+ public void setRunning(boolean running) {
+ this.running = running;
+ }
+
}
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java
index 840b04f..363219d 100644
--- a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java
@@ -31,28 +31,40 @@
import org.eclipse.swt.widgets.Display;
/**
+ * The SWTTimerQueue is a queue of timers. It has been implemented as a linked
+ * list of SWTTimer objects.
+ *
* @author Lance Good
*/
public class SWTTimerQueue implements Runnable {
- static SWTTimerQueue instance;
+ private static SWTTimerQueue instance;
- Display display = null;
+ private final Display display;
- SWTTimer firstTimer;
- boolean running;
+ private SWTTimer firstTimer;
+ private boolean running;
/**
- * Constructor for TimerQueue.
+ * Creates a timer queue that will be attached the the provided display.
+ * It's Timers are expected to modify only this display, or none.
+ *
+ * @param display the display that will get updated by this queue's timers.
*/
public SWTTimerQueue(final Display display) {
- super();
-
this.display = display;
// Now start the TimerQueue thread.
start();
}
+ /**
+ * Returns the singleton instance of the SWTTimerQueue. Take note that even
+ * when called with different displays it will always return the same result
+ * as the first call.
+ *
+ * @param display display to associate with this Timer Queue's Activities
+ * @return singleton instance of SWTTimerQueue
+ */
public static SWTTimerQueue sharedInstance(final Display display) {
if (instance == null) {
instance = new SWTTimerQueue(display);
@@ -60,107 +72,148 @@
return instance;
}
+ /**
+ * Starts the timer queue. If it is already running, a RuntimeException will
+ * be thrown.
+ */
synchronized void start() {
if (running) {
- throw new RuntimeException("Can't start a TimerQueue " + "that is already running");
+ throw new RuntimeException("Can't start a TimerQueue that is already running");
}
- else {
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- final Thread timerThread = new Thread(SWTTimerQueue.this, "TimerQueue");
- timerThread.setDaemon(true);
- timerThread.setPriority(Thread.NORM_PRIORITY);
- timerThread.start();
- }
- });
- running = true;
- }
+
+ // Ensures that the Thread will be started from the display thread.
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ final Thread timerThread = new Thread(SWTTimerQueue.this, "TimerQueue");
+ timerThread.setDaemon(true);
+ timerThread.setPriority(Thread.NORM_PRIORITY);
+ timerThread.start();
+ }
+ });
+
+ running = true;
}
+ /**
+ * Stops the TimerQueue Thread.
+ */
synchronized void stop() {
running = false;
notify();
}
+ /**
+ * Adds the provided timer to the queue of scheduled timers.
+ *
+ * @param timer timer to add
+ * @param expirationTime time at which the timer is to be stopped and
+ * removed from the queue. Given in unix time.
+ */
synchronized void addTimer(final SWTTimer timer, final long expirationTime) {
- SWTTimer previousTimer;
- SWTTimer nextTimer;
+ // If the Timer is already in the queue, then do nothing
+ if (!timer.isRunning()) {
+ insertTimer(timer, expirationTime);
- // If the Timer is already in the queue, then ignore the add.
- if (timer.running) {
- return;
+ timer.setExpirationTime(expirationTime);
+
+ timer.setRunning(true);
+ notify();
}
+ }
- previousTimer = null;
- nextTimer = firstTimer;
-
- // Insert the Timer into the linked list in the order they will
- // expire. If two timers expire at the same time, put the newer entry
- // later so they expire in the order they came in.
-
- while (nextTimer != null) {
- if (nextTimer.expirationTime > expirationTime) {
- break;
- }
-
- previousTimer = nextTimer;
- nextTimer = nextTimer.nextTimer;
- }
-
+ /**
+ * Insert the Timer into the queue in the order they will expire. If
+ * multiple timers are set to expire at the same time, it will insert it
+ * after the last one; that way they expire in the order they came in.
+ *
+ * @param timer timer to insert into the queue
+ * @param expirationTime time in UNIX time at which the new timer should
+ * expire
+ */
+ private void insertTimer(final SWTTimer timer, final long expirationTime) {
+ SWTTimer previousTimer = findLastTimerExpiringBefore(expirationTime);
if (previousTimer == null) {
firstTimer = timer;
}
else {
- previousTimer.nextTimer = timer;
+ timer.setNextTimer(previousTimer.getNextTimer());
+ previousTimer.setNextTimer(timer);
}
-
- timer.expirationTime = expirationTime;
- timer.nextTimer = nextTimer;
- timer.running = true;
- notify();
}
- synchronized void removeTimer(final SWTTimer timer) {
- SWTTimer previousTimer;
- SWTTimer nextTimer;
- boolean found;
+ /**
+ * Finds the last timer that will expire before or at the given expiration
+ * time. If there are multiple timers expiring at the same time, the last
+ * one in the queue will be returned.
+ *
+ * @param expirationTime expiration to compare against timers in the queue
+ * @return last timer that will expire before or at the given expiration
+ * time
+ */
+ private SWTTimer findLastTimerExpiringBefore(final long expirationTime) {
+ SWTTimer previousTimer = null;
+ SWTTimer nextTimer = firstTimer;
- if (!timer.running) {
- return;
- }
-
- previousTimer = null;
- nextTimer = firstTimer;
- found = false;
-
- while (nextTimer != null) {
- if (nextTimer == timer) {
- found = true;
- break;
- }
-
+ while (nextTimer != null && nextTimer.getExpirationTime() > expirationTime) {
previousTimer = nextTimer;
- nextTimer = nextTimer.nextTimer;
+ nextTimer = nextTimer.getNextTimer();
}
- if (!found) {
+ return previousTimer;
+
+ }
+
+ /**
+ * Removes the provided timer from the Timer Queue. If it is not found, then
+ * nothing happens.
+ *
+ * @param timer timer to remove from the queue
+ */
+ synchronized void removeTimer(final SWTTimer timer) {
+ if (!timer.isRunning()) {
return;
}
- if (previousTimer == null) {
- firstTimer = timer.nextTimer;
+ if (timer == firstTimer) {
+ firstTimer = timer.getNextTimer();
}
else {
- previousTimer.nextTimer = timer.nextTimer;
+ SWTTimer previousTimer = findLastTimerBefore(timer);
+ if (previousTimer != null) {
+ previousTimer.setNextTimer(timer.getNextTimer());
+ }
}
- timer.expirationTime = 0;
- timer.nextTimer = null;
- timer.running = false;
+ timer.setExpirationTime(0);
+ timer.setNextTimer(null);
+ timer.setRunning(false);
+ }
+
+ /**
+ * Finds the timer that immediately precedes the provided timer in the
+ * queue.
+ *
+ * @param timer to search for
+ * @return timer immediately preceding found timer, or null if not found
+ */
+ private SWTTimer findLastTimerBefore(final SWTTimer timer) {
+ SWTTimer previousTimer = null;
+ SWTTimer currentTimer = firstTimer;
+
+ while (currentTimer != null) {
+ if (currentTimer == timer) {
+ return previousTimer;
+ }
+
+ previousTimer = currentTimer;
+ currentTimer = currentTimer.getNextTimer();
+ }
+
+ return null;
}
synchronized boolean containsTimer(final SWTTimer timer) {
- return timer.running;
+ return timer.isRunning();
}
/**
@@ -183,7 +236,7 @@
}
currentTime = System.currentTimeMillis();
- timeToWait = timer.expirationTime - currentTime;
+ timeToWait = timer.getExpirationTime() - currentTime;
if (timeToWait <= 0) {
try {
@@ -211,13 +264,14 @@
wait(1);
}
catch (final InterruptedException e) {
+
}
}
} while (timeToWait <= 0);
return timeToWait;
}
-
+
public synchronized void run() {
long timeToWait;
@@ -237,13 +291,18 @@
SWTTimer timer = firstTimer;
while (timer != null) {
timer.cancelEventOverride();
- timer = timer.nextTimer;
+ timer = timer.getNextTimer();
}
display.asyncExec(new SWTTimerQueueRestart(display));
throw td;
}
}
+ /**
+ * Generates a string handy for debugging the contents of the timer queue.
+ *
+ * @return String representation of the queue for use in debugging
+ */
public synchronized String toString() {
StringBuffer buf;
SWTTimer nextTimer;
@@ -255,7 +314,7 @@
while (nextTimer != null) {
buf.append(nextTimer.toString());
- nextTimer = nextTimer.nextTimer;
+ nextTimer = nextTimer.getNextTimer();
if (nextTimer != null) {
buf.append(", ");
}
@@ -270,26 +329,29 @@
* restart.
*/
protected static class SWTTimerQueueRestart implements Runnable {
- boolean attemptedStart;
+ /** Tracks whether a restart has been attempted. */
+ private boolean attemptedStart;
- Display display = null;
+ private final Display display;
public SWTTimerQueueRestart(final Display display) {
this.display = display;
}
- public synchronized void run() {
- // Only try and restart the q once.
- if (!attemptedStart) {
- final SWTTimerQueue q = SWTTimerQueue.sharedInstance(display);
-
- synchronized (q) {
- if (!q.running) {
- q.start();
- }
- }
- attemptedStart = true;
+ public synchronized void run() {
+ if (attemptedStart) {
+ return;
}
+
+ final SWTTimerQueue q = SWTTimerQueue.sharedInstance(display);
+
+ synchronized (q) {
+ if (!q.running) {
+ q.start();
+ }
+ }
+
+ attemptedStart = true;
}
}