1 | // Jomic - a viewer for comic book archives. |
2 | // Copyright (C) 2004-2011 Thomas Aglassinger |
3 | // |
4 | // This program is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by |
6 | // the Free Software Foundation, either version 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
9 | // This program is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // GNU General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | package net.sf.jomic.tools; |
17 | |
18 | import javax.swing.SwingUtilities; |
19 | |
20 | /** |
21 | * This is the 3rd version of SwingWorker (also known as SwingWorker 3), an abstract class that you |
22 | * subclass to perform GUI-related work in a dedicated thread. For instructions on and examples of |
23 | * using this class, see: http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html Note |
24 | * that the API changed slightly in the 3rd version: You must now invoke start() on the SwingWorker |
25 | * after creating it. |
26 | */ |
27 | public abstract class SwingWorker |
28 | { |
29 | |
30 | private ThreadVar threadVar; |
31 | private Object value; |
32 | |
33 | /** |
34 | * Start a thread that will call the <code>construct</code> method and then exit. |
35 | */ |
36 | public SwingWorker() { |
37 | final Runnable doFinished = |
38 | new Runnable() |
39 | { |
40 | public void run() { |
41 | finished(); |
42 | } |
43 | }; |
44 | |
45 | Runnable doConstruct = |
46 | new Runnable() |
47 | { |
48 | public void run() { |
49 | try { |
50 | setValue(construct()); |
51 | } finally { |
52 | threadVar.clear(); |
53 | } |
54 | |
55 | SwingUtilities.invokeLater(doFinished); |
56 | } |
57 | }; |
58 | |
59 | Thread t = new Thread(doConstruct); |
60 | |
61 | threadVar = new ThreadVar(t); |
62 | } |
63 | |
64 | /** |
65 | * Set the value produced by worker thread. |
66 | */ |
67 | private synchronized void setValue(Object x) { |
68 | value = x; |
69 | } |
70 | |
71 | /** |
72 | * Return the value created by the <code>construct</code> method. Returns null if either the |
73 | * constructing thread or the current thread was interrupted before a value was produced. |
74 | * |
75 | * @return the value created by the <code>construct</code> method |
76 | */ |
77 | public Object get() { |
78 | Object result = null; |
79 | boolean gotResult = false; |
80 | |
81 | while (!gotResult) { |
82 | Thread t = threadVar.get(); |
83 | |
84 | if (t == null) { |
85 | result = getValue(); |
86 | gotResult = true; |
87 | } else { |
88 | try { |
89 | t.join(); |
90 | } catch (InterruptedException e) { |
91 | // Propagate |
92 | Thread.currentThread().interrupt(); |
93 | result = null; |
94 | gotResult = true; |
95 | } |
96 | } |
97 | } |
98 | return result; |
99 | } |
100 | |
101 | /** |
102 | * Get the value produced by the worker thread, or null if it hasn't been constructed yet. |
103 | */ |
104 | protected synchronized Object getValue() { |
105 | return value; |
106 | } |
107 | |
108 | /** |
109 | * Compute the value to be returned by the <code>get</code> method. |
110 | */ |
111 | public abstract Object construct(); |
112 | |
113 | /** |
114 | * Called on the event dispatching thread (not on the worker thread) after the <code>construct</code> |
115 | * method has returned. |
116 | */ |
117 | public void finished() { |
118 | // do nothing |
119 | } |
120 | |
121 | /** |
122 | * A new method that interrupts the worker thread. Call this method to force the worker to stop |
123 | * what it's doing. |
124 | */ |
125 | public void interrupt() { |
126 | Thread t = threadVar.get(); |
127 | |
128 | if (t != null) { |
129 | t.interrupt(); |
130 | } |
131 | threadVar.clear(); |
132 | } |
133 | |
134 | /** |
135 | * Start the worker thread. |
136 | */ |
137 | public void start() { |
138 | Thread t = threadVar.get(); |
139 | |
140 | if (t != null) { |
141 | t.start(); |
142 | } |
143 | } |
144 | |
145 | /** |
146 | * Class to maintain reference to current worker thread under separate synchronization control. |
147 | */ |
148 | private static class ThreadVar |
149 | { |
150 | private Thread thread; |
151 | |
152 | ThreadVar(Thread t) { |
153 | thread = t; |
154 | } |
155 | |
156 | synchronized Thread get() { |
157 | return thread; |
158 | } |
159 | |
160 | synchronized void clear() { |
161 | thread = null; |
162 | } |
163 | } |
164 | } |