3 TrakEM2 plugin for ImageJ(C).
4 Copyright (C) 2005,2006 Albert Cardona and Rodney Douglas.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 You may contact Albert Cardona at acardona at ini.phys.ethz.ch
20 Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
23 package ini
.trakem2
.utils
;
25 import ini
.trakem2
.ControlWindow
;
26 import ini
.trakem2
.Project
;
27 import ini
.trakem2
.persistence
.Loader
;
28 import ini
.trakem2
.utils
.Utils
;
29 import java
.util
.ArrayList
;
31 /** Sets a Worker thread to work, and waits until it finishes, blocking all user interface input until then, except for zoom and pan, for all given projects. */
32 public class Bureaucrat
extends Thread
{
33 private Worker worker
;
34 private Thread worker_thread
;
36 private Project
[] project
;
37 private boolean started
= false;
38 /** A list of tasks to run when the Worker finishes of quits. */
39 private ArrayList
<Runnable
> post_tasks
= new ArrayList
<Runnable
>();
41 /** Registers itself in the project loader job queue. */
42 private Bureaucrat(ThreadGroup tg
, Worker worker
, Project project
) {
43 this(tg
, worker
, new Project
[]{project
});
45 private Bureaucrat(ThreadGroup tg
, Worker worker
, Project
[] project
) {
46 super(tg
, "T2-Bureaucrat");
47 setPriority(Thread
.NORM_PRIORITY
);
49 this.worker_thread
= new Thread(tg
, worker
, worker
.getThreadName());
50 this.worker_thread
.setPriority(NORM_PRIORITY
);
51 worker
.setThread(worker_thread
);
52 this.project
= project
;
53 onset
= System
.currentTimeMillis();
54 for (int i
=0; i
<project
.length
; i
++) {
55 project
[i
].setReceivesInput(false);
56 project
[i
].getLoader().addJob(this);
60 /** Creates but does not start the Bureaucrat thread. */
61 static public Bureaucrat
create(Worker worker
, Project project
) {
62 return create (worker
, new Project
[]{project
});
65 /** Creates but does not start the Bureaucrat thread. */
66 static public Bureaucrat
create(Worker worker
, Project
[] project
) {
67 ThreadGroup tg
= new ThreadGroup("T2-Bureaucrat for " + worker
.getTaskName());
68 return new Bureaucrat(tg
, worker
, project
);
71 /** Creates and start the Bureaucrat thread. */
72 static public Bureaucrat
createAndStart(Worker worker
, Project project
) {
73 return createAndStart(worker
, new Project
[]{project
});
76 /** Creates and start the Bureaucrat thread. */
77 static public Bureaucrat
createAndStart(Worker worker
, Project
[] project
) {
78 ThreadGroup tg
= new ThreadGroup("T2-Bureaucrat for " + worker
.getTaskName());
79 Bureaucrat burro
= new Bureaucrat(tg
, worker
, project
);
80 burro
.goHaveBreakfast();
84 /** Starts the Bureaucrat thread: sets the worker to work and monitors it until it finishes.*/
85 public void goHaveBreakfast() {
86 worker_thread
.start();
87 // Make sure we start AFTER the worker has started.
88 while (!worker
.hasStarted()) {
89 try { Thread
.currentThread().sleep(50); } catch (InterruptedException ie
) { ie
.printStackTrace(); }
92 // Make sure we return AFTER having started.
94 try { Thread
.currentThread().sleep(50); } catch (InterruptedException ie
) { ie
.printStackTrace(); }
97 private void cleanup() {
98 Utils
.showProgress(1); // cleanup all possible interruptions
99 for (int i
=0; i
<project
.length
; i
++) {
100 project
[i
].getLoader().removeJob(this);
101 project
[i
].setReceivesInput(true);
106 // wait until worker starts
107 while (!worker
.isWorking()) {
108 try { Thread
.sleep(50); } catch (InterruptedException ie
) {}
109 if (worker
.hasQuitted() || worker_thread
.isInterrupted()) {
110 //Utils.log("Cleaning up...");
113 //Utils.log("...done.");
117 ControlWindow
.startWaitingCursor();
118 int sandwitch
= ControlWindow
.isGUIEnabled() ?
100 : 5000; // 1 second or 5
119 Utils
.showStatus("Started processing: " + worker
.getTaskName(), false); // don't steal focus, ever
120 final StringBuffer sb
= new StringBuffer("Processing... ").append(worker
.getTaskName()).append(" - ");
121 final int base_len
= sb
.length();
122 while (worker
.isWorking() && !worker
.hasQuitted()) {
123 try { Thread
.sleep(sandwitch
); } catch (InterruptedException ie
) {}
124 float elapsed_seconds
= (System
.currentTimeMillis() - onset
) / 1000.0f
;
125 if (elapsed_seconds
< 60) {
126 sb
.append(elapsed_seconds
).append(" seconds");
128 sb
.append(elapsed_seconds
/ 60).append("' ").append(elapsed_seconds
% 60).append("''");
130 Utils
.showStatus(sb
.toString(), false); // don't steal focus
131 // Increment up to 1 second
132 if (sandwitch
< 1000) sandwitch
+= 100;
134 sb
.setLength(base_len
);
136 ControlWindow
.endWaitingCursor();
137 Utils
.showStatus("Done " + worker
.getTaskName(), false); // don't steal focus
139 if (null != post_tasks
) {
140 for (final Runnable r
: post_tasks
) {
143 } catch (Throwable t
) {
148 } catch(Throwable t
) {
153 /** Returns the task the worker is currently executing, which may change over time. */
154 public String
getTaskName() {
155 return worker
.getTaskName();
157 /** Waits until worker finishes before returning.
158 * Calls quit() on the Worker and interrupt() on each threads in this ThreadGroup and subgroups. */
162 // Cancel post tasks:
163 synchronized (post_tasks
) {
168 Utils
.log2("ThreadGroup is " + getThreadGroup());
170 Utils
.log2("ThreadGroup active thread count: " + getThreadGroup().activeCount());
171 Utils
.log2("ThreadGroup active group count: " + getThreadGroup().activeGroupCount());
173 Thread
[] active
= new Thread
[getThreadGroup().activeCount()];
174 int count
= getThreadGroup().enumerate(active
);
175 Utils
.log2("Active threads: " + count
);
176 for (int i
=0; i
< count
; i
++) {
177 Utils
.log2("Active thread: " + active
[i
]);
180 // Set flag to each thread and thread in subgroup to quit:
182 getThreadGroup().interrupt();
184 } catch (Exception e
) {
187 // wait until worker finishes
189 Utils
.log("Waiting for worker to quit...");
190 worker_thread
.join();
191 Utils
.log("Worker quitted.");
192 } catch (InterruptedException ie
) {
195 // wait for all others in a separate thread
196 final ThreadGroup tg
= getThreadGroup();
197 new Thread() { public void run() {
199 // Reasonable effort to join all threads
200 Thread
[] t
= new Thread
[tg
.activeCount() * 2];
201 int len
= tg
.enumerate(t
);
202 for (int i
=0; i
<len
&& i
<t
.length
; i
++) {
203 try { t
[i
].join(); } catch (InterruptedException ie
) {}
205 } catch (Exception e
) {
208 Utils
.showProgress(1);
212 public boolean isActive() {
213 return worker
.isWorking();
215 public Worker
getWorker() {
218 /** Add a task to run after the Worker has finished or quit. Does not accept more tasks once the Worker no longer runs. */
219 public boolean addPostTask(final Runnable task
) {
220 if (worker
.hasQuitted() || null == post_tasks
) return false;
221 synchronized (post_tasks
) {
222 this.post_tasks
.add(task
);