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

Last change on this file since 1811 was 1811, checked in by jttt, 15 years ago

PleaseWait refactoring. Progress is now reported using ProgressMonitor interface, that is available through PleaseWaitRunnable.

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