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

Last change on this file since 13146 was 12675, checked in by Don-vip, 7 years ago

see #15182 - move the Swing-based ProgressMonitor implementations from gui.progress to gui.progress.swing. Progress monitor concept is used in very large parts of JOSM, a console-based implementation could be added later

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