001: //The contents of this file are subject to the Mozilla Public License Version 1.1
002: //(the "License"); you may not use this file except in compliance with the
003: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
004: //
005: //Software distributed under the License is distributed on an "AS IS" basis,
006: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
007: //for the specific language governing rights and
008: //limitations under the License.
009: //
010: //The Original Code is "The Columba Project"
011: //
012: //The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
013: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
014: //
015: //All Rights Reserved.
016: package org.columba.core.base;
017:
018: import javax.swing.SwingUtilities;
019:
020: /**
021: * This is the 3rd version of SwingWorker (also known as SwingWorker 3), an
022: * abstract class that you subclass to perform GUI-related work in a dedicated
023: * thread. For instructions on using this class, see:
024: *
025: * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
026: *
027: * Note that the API changed slightly in the 3rd version: You must now invoke
028: * start() on the SwingWorker after creating it.
029: */
030: public abstract class SwingWorker {
031: protected Object value; // see getValue(), setValue()
032:
033: protected Thread thread;
034:
035: protected boolean cancel;
036:
037: protected ThreadVar threadVar;
038:
039: /**
040: * Start a thread that will call the <code>construct</code> method and
041: * then exit.
042: */
043: public SwingWorker() {
044: cancel = false;
045:
046: final Runnable doFinished = new Runnable() {
047: public void run() {
048: finished();
049: }
050: };
051:
052: Runnable doConstruct = new Runnable() {
053: public void run() {
054: try {
055: setValue(construct());
056: } finally {
057: // threadVar;
058: }
059:
060: SwingUtilities.invokeLater(doFinished);
061: }
062: };
063:
064: Thread t = new Thread(doConstruct);
065:
066: // following java guidelines I'm setting this to low priority
067: // -> this should make the gui more responsive, because the
068: // -> background worker has low priority whereas the gui worker
069: // -> has normal priority
070: t.setPriority(Thread.MIN_PRIORITY);
071:
072: threadVar = new ThreadVar(t);
073: }
074:
075: /**
076: * Get the value produced by the worker thread, or null if it hasn't been
077: * constructed yet.
078: */
079: protected synchronized Object getValue() {
080: return value;
081: }
082:
083: /**
084: * Set the value produced by worker thread
085: */
086: synchronized void setValue(Object x) {
087: value = x;
088: }
089:
090: public Thread getThread() {
091: return threadVar.get();
092: }
093:
094: public ThreadVar getThreadVar() {
095: return threadVar;
096: }
097:
098: public boolean getCancel() {
099: return cancel;
100: }
101:
102: public void setCancel(boolean b) {
103: cancel = b;
104: }
105:
106: protected boolean isCanceled() {
107: return cancel;
108: }
109:
110: /**
111: * Compute the value to be returned by the <code>get</code> method.
112: */
113: public abstract Object construct();
114:
115: /**
116: * Called on the event dispatching thread (not on the worker thread) after
117: * the <code>construct</code> method has returned.
118: */
119: public void finished() {
120: // nothing to do
121: }
122:
123: /**
124: * A new method that interrupts the worker thread. Call this method to force
125: * the worker to stop what it's doing.
126: */
127: public void interrupt() {
128: Thread t = threadVar.get();
129:
130: if (t != null) {
131: t.interrupt();
132: }
133:
134: threadVar.clear();
135: }
136:
137: /**
138: * Return the value created by the <code>construct</code> method. Returns
139: * null if either the constructing thread or the current thread was
140: * interrupted before a value was produced.
141: *
142: * @return the value created by the <code>construct</code> method
143: */
144: public Object get() {
145: while (true) {
146: Thread t = threadVar.get();
147:
148: if (t == null) {
149: return getValue();
150: }
151:
152: try {
153: t.join();
154: } catch (InterruptedException e) {
155: Thread.currentThread().interrupt(); // propagate
156:
157: return null;
158: }
159: }
160: }
161:
162: /**
163: * Start the worker thread.
164: */
165: public Thread start() {
166:
167: thread = threadVar.get();
168:
169: if (thread != null) {
170: thread.start();
171:
172: return thread;
173: }
174:
175: return null;
176: }
177:
178: /**
179: * Class to maintain reference to current worker thread under separate
180: * synchronization control.
181: */
182: public static class ThreadVar {
183: private Thread thread;
184:
185: ThreadVar(Thread t) {
186: thread = t;
187: }
188:
189: synchronized Thread get() {
190: return new Thread(thread);
191: }
192:
193: synchronized void clear() {
194: thread = null;
195: }
196: }
197: }
|