001: /*
002: * SwingWorker.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.underworldlabs.swing.util;
023:
024: import javax.swing.SwingUtilities;
025:
026: /* ----------------------------------------------------------
027: * CVS NOTE: Changes to the CVS repository prior to the
028: * release of version 3.0.0beta1 has meant a
029: * resetting of CVS revision numbers.
030: * ----------------------------------------------------------
031: */
032:
033: /**
034: * This is the 3rd version of SwingWorker (also known as
035: * SwingWorker 3), an abstract class that you subclass to
036: * perform GUI-related work in a dedicated thread. For
037: * instructions on using this class, see:
038: *
039: * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
040: *
041: * Note that the API changed slightly in the 3rd version:
042: * You must now invoke start() on the SwingWorker after
043: * creating it.
044: */
045: public abstract class SwingWorker {
046: private Object value; // see getValue(), setValue()
047: private Thread thread;
048:
049: /**
050: * Class to maintain reference to current worker thread
051: * under separate synchronization control.
052: */
053: private static class ThreadVar {
054: private Thread thread;
055:
056: ThreadVar(Thread t) {
057: thread = t;
058: }
059:
060: synchronized Thread get() {
061: return thread;
062: }
063:
064: synchronized void clear() {
065: thread = null;
066: }
067: }
068:
069: private ThreadVar threadVar;
070:
071: /**
072: * Get the value produced by the worker thread, or null if it
073: * hasn't been constructed yet.
074: */
075: protected synchronized Object getValue() {
076: return value;
077: }
078:
079: /**
080: * Set the value produced by worker thread
081: */
082: private synchronized void setValue(Object x) {
083: value = x;
084: }
085:
086: /**
087: * Compute the value to be returned by the <code>get</code> method.
088: */
089: public abstract Object construct();
090:
091: /**
092: * Called on the event dispatching thread (not on the worker thread)
093: * after the <code>construct</code> method has returned.
094: */
095: public void finished() {
096: }
097:
098: /**
099: * A new method that interrupts the worker thread. Call this method
100: * to force the worker to stop what it's doing.
101: */
102: public void interrupt() {
103: Thread t = threadVar.get();
104: if (t != null) {
105: t.interrupt();
106: }
107: threadVar.clear();
108: }
109:
110: /**
111: * Return the value created by the <code>construct</code> method.
112: * Returns null if either the constructing thread or the current
113: * thread was interrupted before a value was produced.
114: *
115: * @return the value created by the <code>construct</code> method
116: */
117: public Object get() {
118: while (true) {
119: Thread t = threadVar.get();
120: if (t == null) {
121: return getValue();
122: }
123: try {
124: t.join();
125: } catch (InterruptedException e) {
126: Thread.currentThread().interrupt(); // propagate
127: return null;
128: }
129: }
130: }
131:
132: /**
133: * Start a thread that will call the <code>construct</code> method
134: * and then exit.
135: */
136: public SwingWorker() {
137: final Runnable doFinished = new Runnable() {
138: public void run() {
139: finished();
140: }
141: };
142:
143: Runnable doConstruct = new Runnable() {
144: public void run() {
145: try {
146: setValue(construct());
147: } finally {
148: threadVar.clear();
149: }
150:
151: SwingUtilities.invokeLater(doFinished);
152: }
153: };
154:
155: Thread t = new Thread(doConstruct);
156: threadVar = new ThreadVar(t);
157: }
158:
159: /**
160: * Start the worker thread.
161: */
162: public void start() {
163: Thread t = threadVar.get();
164: if (t != null) {
165: t.start();
166: }
167: }
168: }
|