source: josm/trunk/src/org/openstreetmap/josm/gui/progress/AbstractProgressMonitor.java@ 4718

Last change on this file since 4718 was 4718, checked in by jttt, 14 years ago

Add posibility to run please wait runnable tasks in background

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/plain
File size: 10.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.progress;
3
4import java.util.Arrays;
5import java.util.Iterator;
6import java.util.LinkedList;
7import java.util.Queue;
8
9import javax.swing.SwingUtilities;
10
11public abstract class AbstractProgressMonitor implements ProgressMonitor {
12
13 private static class Request {
14 AbstractProgressMonitor originator;
15 int childTicks;
16 double currentValue;
17
18 String title;
19 String customText;
20 String extraText;
21 Boolean intermediate;
22
23 boolean finishRequested;
24 }
25
26 private final CancelHandler cancelHandler;
27
28 protected enum State {INIT, IN_TASK, IN_SUBTASK, FINISHED}
29
30 protected State state = State.INIT;
31
32 int ticksCount;
33 int ticks;
34 private int childTicks;
35
36 private String taskTitle;
37 private String customText;
38 private String extraText;
39 private String shownTitle;
40 private String shownCustomText;
41 private boolean intermediateTask;
42
43 private Queue<Request> requests = new LinkedList<Request>();
44 private AbstractProgressMonitor currentChild;
45 private Request requestedState = new Request();
46
47 protected abstract void doBeginTask();
48 protected abstract void doFinishTask();
49 protected abstract void doSetIntermediate(boolean value);
50 protected abstract void doSetTitle(String title);
51 protected abstract void doSetCustomText(String title);
52
53 protected AbstractProgressMonitor(CancelHandler cancelHandler) {
54 this.cancelHandler = cancelHandler;
55 }
56
57 protected void checkState(State... expectedStates) {
58 for (State s:expectedStates) {
59 if (s == state)
60 return;
61 }
62 throw new ProgressException("Expected states are %s but current state is %s", Arrays.asList(expectedStates).toString(), state);
63 }
64
65 protected void doInEDT(Runnable runnable) {
66 if (SwingUtilities.isEventDispatchThread()) {
67 runnable.run();
68 } else {
69 SwingUtilities.invokeLater(runnable);
70 }
71 }
72
73 /*=======
74 * Tasks
75 =======*/
76
77 public void beginTask(String title) {
78 beginTask(title, DEFAULT_TICKS);
79 }
80
81 public synchronized void beginTask(String title, int ticks) {
82 this.taskTitle = title;
83 checkState(State.INIT);
84 state = State.IN_TASK;
85 doBeginTask();
86 setTicksCount(ticks);
87 resetState();
88 }
89
90 public synchronized void finishTask() {
91 if (state != State.FINISHED) {
92
93 if (state == State.IN_SUBTASK) {
94 requestedState.finishRequested = true;
95 } else {
96 checkState(State.IN_TASK);
97 state = State.FINISHED;
98 doFinishTask();
99 }
100 }
101 }
102
103 public synchronized void invalidate() {
104 if (state == State.INIT) {
105 state = State.FINISHED;
106 doFinishTask();
107 }
108 }
109
110 public synchronized void subTask(final String title) {
111 if (state == State.IN_SUBTASK) {
112 if (title != null) {
113 requestedState.title = title;
114 }
115 requestedState.intermediate = false;
116 } else {
117 checkState(State.IN_TASK);
118 if (title != null) {
119 this.taskTitle = title;
120 resetState();
121 }
122 this.intermediateTask = false;
123 doSetIntermediate(false);
124 }
125 }
126
127 public synchronized void indeterminateSubTask(String title) {
128 if (state == State.IN_SUBTASK) {
129 if (title != null) {
130 requestedState.title = title;
131 }
132 requestedState.intermediate = true;
133 } else {
134 checkState(State.IN_TASK);
135 if (title != null) {
136 this.taskTitle = title;
137 resetState();
138 }
139 this.intermediateTask = true;
140 doSetIntermediate(true);
141 }
142 }
143
144 public synchronized void setCustomText(String text) {
145 if (state == State.IN_SUBTASK) {
146 requestedState.customText = text;
147 } else {
148 this.customText = text;
149 resetState();
150 }
151 }
152
153 public synchronized void setExtraText(String text) {
154 if (state == State.IN_SUBTASK) {
155 requestedState.extraText = text;
156 } else {
157 this.extraText = text;
158 resetState();
159 }
160 }
161
162 /**
163 * Default implementation is empty. Override in subclasses to display the log messages.
164 */
165 public void appendLogMessage(String message) {
166 // do nothing
167 }
168
169 private void resetState() {
170 String newTitle;
171 if (extraText != null) {
172 newTitle = taskTitle + " " + extraText;
173 } else {
174 newTitle = taskTitle;
175 }
176
177 if (newTitle == null?shownTitle != null:!newTitle.equals(shownTitle)) {
178 shownTitle = newTitle;
179 doSetTitle(shownTitle);
180 }
181
182 if (customText == null?shownCustomText != null:!customText.equals(shownCustomText)) {
183 shownCustomText = customText;
184 doSetCustomText(shownCustomText);
185 }
186 doSetIntermediate(intermediateTask);
187 }
188
189 public void cancel() {
190 cancelHandler.cancel();
191 }
192
193 public boolean isCanceled() {
194 return cancelHandler.isCanceled();
195 }
196
197 public void addCancelListener(CancelListener listener) {
198 cancelHandler.addCancelListener(listener);
199 }
200
201 public void removeCancelListener(CancelListener listener) {
202 cancelHandler.removeCancelListener(listener);
203 }
204
205 /*=================
206 * Ticks handling
207 ==================*/
208
209 abstract void updateProgress(double value);
210
211 public synchronized void setTicks(int ticks) {
212 if (ticks >= ticksCount) {
213 ticks = ticksCount - 1;
214 }
215 this.ticks = ticks;
216 internalUpdateProgress(0);
217 }
218
219 public synchronized void setTicksCount(int ticks) {
220 this.ticksCount = ticks;
221 internalUpdateProgress(0);
222 }
223
224 public void worked(int ticks) {
225 if (ticks == ALL_TICKS) {
226 setTicks(this.ticksCount - 1);
227 } else {
228 setTicks(this.ticks + ticks);
229 }
230 }
231
232 private void internalUpdateProgress(double childProgress) {
233 if (childProgress > 1) {
234 childProgress = 1;
235 }
236 checkState(State.IN_TASK, State.IN_SUBTASK);
237 updateProgress(ticksCount == 0?0:(ticks + childProgress * childTicks) / ticksCount);
238 }
239
240 public synchronized int getTicks() {
241 return ticks;
242 }
243
244 public synchronized int getTicksCount() {
245 return ticksCount;
246 }
247
248 /*==========
249 * Subtasks
250 ==========*/
251
252 public synchronized ProgressMonitor createSubTaskMonitor(int ticks, boolean internal) {
253 if (ticks == ALL_TICKS) {
254 ticks = ticksCount - this.ticks;
255 }
256
257 if (state == State.IN_SUBTASK) {
258 Request request = new Request();
259 request.originator = new ChildProgress(this, cancelHandler, internal);
260 request.childTicks = ticks;
261 requests.add(request);
262 return request.originator;
263 } else {
264 checkState(State.IN_TASK);
265 state = State.IN_SUBTASK;
266 this.childTicks = ticks;
267 currentChild = new ChildProgress(this, cancelHandler, internal);
268 return currentChild;
269 }
270 }
271
272 private void applyChildRequest(Request request) {
273 if (request.customText != null) {
274 doSetCustomText(request.customText);
275 }
276
277 if (request.title != null) {
278 doSetTitle(request.title);
279 }
280
281 if (request.intermediate != null) {
282 doSetIntermediate(request.intermediate);
283 }
284
285 internalUpdateProgress(request.currentValue);
286 }
287
288 private void applyThisRequest(Request request) {
289 if (request.finishRequested) {
290 finishTask();
291 } else {
292 if (request.customText != null) {
293 this.customText = request.customText;
294 }
295
296 if (request.title != null) {
297 this.taskTitle = request.title;
298 }
299
300 if (request.intermediate != null) {
301 this.intermediateTask = request.intermediate;
302 }
303
304 if (request.extraText != null) {
305 this.extraText = request.extraText;
306 }
307
308 resetState();
309 }
310 }
311
312 protected synchronized void childFinished(AbstractProgressMonitor child) {
313 checkState(State.IN_SUBTASK);
314 if (currentChild == child) {
315 setTicks(ticks + childTicks);
316 if (requests.isEmpty()) {
317 state = State.IN_TASK;
318 applyThisRequest(requestedState);
319 requestedState = new Request();
320 } else {
321 Request newChild = requests.poll();
322 currentChild = newChild.originator;
323 childTicks = newChild.childTicks;
324 applyChildRequest(newChild);
325 }
326 } else {
327 Iterator<Request> it = requests.iterator();
328 while (it.hasNext()) {
329 if (it.next().originator == child) {
330 it.remove();
331 return;
332 }
333 }
334 throw new ProgressException("Subtask %s not found", child);
335 }
336 }
337
338 private Request getRequest(AbstractProgressMonitor child) {
339 for (Request request:requests) {
340 if (request.originator == child)
341 return request;
342 }
343 throw new ProgressException("Subtask %s not found", child);
344 }
345
346 protected synchronized void childSetProgress(AbstractProgressMonitor child, double value) {
347 checkState(State.IN_SUBTASK);
348 if (currentChild == child) {
349 internalUpdateProgress(value);
350 } else {
351 getRequest(child).currentValue = value;
352 }
353 }
354
355 protected synchronized void childSetTitle(AbstractProgressMonitor child, String title) {
356 checkState(State.IN_SUBTASK);
357 if (currentChild == child) {
358 doSetTitle(title);
359 } else {
360 getRequest(child).title = title;
361 }
362 }
363
364 protected synchronized void childSetCustomText(AbstractProgressMonitor child, String customText) {
365 checkState(State.IN_SUBTASK);
366 if (currentChild == child) {
367 doSetCustomText(customText);
368 } else {
369 getRequest(child).customText = customText;
370 }
371 }
372
373 protected synchronized void childSetIntermediate(AbstractProgressMonitor child, boolean value) {
374 checkState(State.IN_SUBTASK);
375 if (currentChild == child) {
376 doSetIntermediate(value);
377 } else {
378 getRequest(child).intermediate = value;
379 }
380 }
381}
Note: See TracBrowser for help on using the repository browser.