001: package net.xoetrope.xui.helper;
002:
003: import javax.swing.SwingUtilities;
004:
005: /**
006: * This is the 3rd version of SwingWorker (also known as
007: * SwingWorker 3), an abstract class that you subclass to
008: * perform GUI-related work in a dedicated thread. For
009: * instructions on using this class, see:
010: *
011: * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
012: *
013: * Note that the API changed slightly in the 3rd version:
014: * You must now invoke start() on the SwingWorker after
015: * creating it.
016: * $Revision: 1.2 $
017: */
018: public abstract class SwingWorker {
019: private Object value; // see getValue(), setValue()
020: private Thread thread;
021: private Object extraValue;
022:
023: /**
024: * Class to maintain reference to current worker thread
025: * under separate synchronization control.
026: */
027: private static class ThreadVar {
028: private Thread thread;
029:
030: ThreadVar(Thread t) {
031: thread = t;
032: }
033:
034: synchronized Thread get() {
035: return thread;
036: }
037:
038: synchronized void clear() {
039: thread = null;
040: }
041: }
042:
043: private ThreadVar threadVar;
044:
045: /**
046: * Get the value produced by the worker thread, or null if it
047: * hasn't been constructed yet.
048: */
049: protected synchronized Object getValue() {
050: return value;
051: }
052:
053: /**
054: * Set the value produced by worker thread
055: */
056: private synchronized void setValue(Object x) {
057: value = x;
058: }
059:
060: /**
061: * Set an extra value
062: * @param x the object to maintain a reference to
063: */
064: public synchronized void setExtraValue(Object x) {
065: extraValue = x;
066: }
067:
068: /**
069: * Get the extra value reference
070: * @return the reference
071: */
072: public synchronized Object getExtraValue() {
073: return extraValue;
074: }
075:
076: /**
077: * Compute the value to be returned by the <code>get</code> method.
078: */
079: public abstract Object construct();
080:
081: /**
082: * Called on the event dispatching thread (not on the worker thread)
083: * after the <code>construct</code> method has returned.
084: */
085: public void finished() {
086: }
087:
088: /**
089: * A new method that interrupts the worker thread. Call this method
090: * to force the worker to stop what it's doing.
091: */
092: public void interrupt() {
093: Thread t = threadVar.get();
094: if (t != null) {
095: t.interrupt();
096: }
097: threadVar.clear();
098: }
099:
100: /**
101: * Return the value created by the <code>construct</code> method.
102: * Returns null if either the constructing thread or the current
103: * thread was interrupted before a value was produced.
104: *
105: * @return the value created by the <code>construct</code> method
106: */
107: public Object get() {
108: while (true) {
109: Thread t = threadVar.get();
110: if (t == null) {
111: return getValue();
112: }
113: try {
114: t.join();
115: } catch (InterruptedException e) {
116: Thread.currentThread().interrupt(); // propagate
117: return null;
118: }
119: }
120: }
121:
122: /**
123: * Start a thread that will call the <code>construct</code> method
124: * and then exit.
125: */
126: public SwingWorker() {
127: final Runnable doFinished = new Runnable() {
128: public void run() {
129: finished();
130: }
131: };
132:
133: Runnable doConstruct = new Runnable() {
134: public void run() {
135: try {
136: setValue(construct());
137: } finally {
138: threadVar.clear();
139: }
140:
141: SwingUtilities.invokeLater(doFinished);
142: }
143: };
144:
145: Thread t = new Thread(doConstruct);
146: threadVar = new ThreadVar(t);
147: }
148:
149: /**
150: * Start the worker thread.
151: */
152: public void start() {
153: Thread t = threadVar.get();
154: if (t != null) {
155: t.start();
156: }
157: }
158: }
|