source: josm/trunk/src/org/openstreetmap/josm/gui/progress/PleaseWaitProgressMonitor.java@ 12369

Last change on this file since 12369 was 12369, checked in by michael2402, 7 years ago

Javadoc for gui.progress package

  • Property svn:eol-style set to native
File size: 12.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.progress;
3
4import java.awt.Component;
5import java.awt.GraphicsEnvironment;
6import java.awt.event.ActionListener;
7import java.awt.event.WindowAdapter;
8import java.awt.event.WindowEvent;
9import java.awt.event.WindowListener;
10
11import javax.swing.SwingUtilities;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.gui.MapFrame;
15import org.openstreetmap.josm.gui.MapStatus.BackgroundProgressMonitor;
16import org.openstreetmap.josm.gui.PleaseWaitDialog;
17import org.openstreetmap.josm.gui.util.GuiHelper;
18import org.openstreetmap.josm.tools.bugreport.BugReport;
19
20/**
21 * A progress monitor used in {@link org.openstreetmap.josm.gui.PleaseWaitRunnable}.
22 * <p>
23 * Progress is displayed in a dialog window ({@link PleaseWaitDialog}).
24 */
25public class PleaseWaitProgressMonitor extends AbstractProgressMonitor {
26
27 /**
28 * Implemented by both foreground dialog and background progress dialog (in status bar)
29 */
30 public interface ProgressMonitorDialog {
31 /**
32 * Sets the visibility of this dialog
33 * @param visible The visibility, <code>true</code> to show it, <code>false</code> to hide it
34 */
35 void setVisible(boolean visible);
36
37 /**
38 * Updates the progress value to the specified progress.
39 * @param progress The progress as integer. Between 0 and {@link PleaseWaitProgressMonitor#PROGRESS_BAR_MAX}
40 */
41 void updateProgress(int progress);
42
43 /**
44 * Sets the description of what is done
45 * @param text The description of the task
46 */
47 void setCustomText(String text);
48
49 /**
50 * Sets the current action that is done
51 * @param text The current action
52 */
53 void setCurrentAction(String text);
54
55 /**
56 * Display that the current progress cannot be determined
57 * @param newValue wether the progress cannot be determined
58 */
59 void setIndeterminate(boolean newValue);
60
61 /**
62 * Append a message to the progress log
63 * <p>
64 * TODO Not implemented properly in background monitor, log message will get lost if progress runs in background
65 * @param message The message
66 */
67 void appendLogMessage(String message);
68 }
69
70 /**
71 * The maximum value the progress bar that displays the current progress should have.
72 */
73 public static final int PROGRESS_BAR_MAX = 10_000;
74 private final Component dialogParent;
75
76 private int currentProgressValue;
77 private String customText;
78 private String title;
79 private boolean indeterminate;
80
81 private boolean isInBackground;
82 private PleaseWaitDialog dialog;
83 private String windowTitle;
84 protected ProgressTaskId taskId;
85
86 private boolean cancelable;
87
88 private void doInEDT(Runnable runnable) {
89 // This must be invoke later even if current thread is EDT because inside there is dialog.setVisible
90 // which freeze current code flow until modal dialog is closed
91 SwingUtilities.invokeLater(() -> {
92 try {
93 runnable.run();
94 } catch (RuntimeException e) { // NOPMD
95 throw BugReport.intercept(e).put("monitor", this);
96 }
97 });
98 }
99
100 private void setDialogVisible(boolean visible) {
101 if (dialog.isVisible() != visible) {
102 dialog.setVisible(visible);
103 }
104 }
105
106 private ProgressMonitorDialog getDialog() {
107
108 BackgroundProgressMonitor backgroundMonitor = null;
109 MapFrame map = Main.map;
110 if (map != null) {
111 backgroundMonitor = map.statusLine.progressMonitor;
112 }
113
114 if (backgroundMonitor != null) {
115 backgroundMonitor.setVisible(isInBackground);
116 }
117 if (dialog != null) {
118 setDialogVisible(!isInBackground || backgroundMonitor == null);
119 }
120
121 if (isInBackground && backgroundMonitor != null) {
122 backgroundMonitor.setVisible(true);
123 if (dialog != null) {
124 setDialogVisible(false);
125 }
126 return backgroundMonitor;
127 } else if (backgroundMonitor != null) {
128 backgroundMonitor.setVisible(false);
129 if (dialog != null) {
130 setDialogVisible(true);
131 }
132 return dialog;
133 } else if (dialog != null) {
134 setDialogVisible(true);
135 return dialog;
136 } else
137 return null;
138 }
139
140 /**
141 * Constructs a new {@code PleaseWaitProgressMonitor}.
142 */
143 public PleaseWaitProgressMonitor() {
144 this("");
145 }
146
147 /**
148 * Constructs a new {@code PleaseWaitProgressMonitor}.
149 * @param windowTitle window title
150 */
151 public PleaseWaitProgressMonitor(String windowTitle) {
152 this(Main.parent);
153 this.windowTitle = windowTitle;
154 }
155
156 /**
157 * Constructs a new {@code PleaseWaitProgressMonitor}.
158 * @param dialogParent component to get parent frame from
159 */
160 public PleaseWaitProgressMonitor(Component dialogParent) {
161 super(new CancelHandler());
162 if (GraphicsEnvironment.isHeadless()) {
163 this.dialogParent = dialogParent;
164 } else {
165 this.dialogParent = GuiHelper.getFrameForComponent(dialogParent);
166 }
167 this.cancelable = true;
168 }
169
170 /**
171 * Constructs a new {@code PleaseWaitProgressMonitor}.
172 * @param dialogParent component to get parent frame from
173 * @param windowTitle window title
174 */
175 public PleaseWaitProgressMonitor(Component dialogParent, String windowTitle) {
176 this(GuiHelper.getFrameForComponent(dialogParent));
177 this.windowTitle = windowTitle;
178 }
179
180 private final ActionListener cancelListener = e -> cancel();
181
182 private final ActionListener inBackgroundListener = e -> {
183 isInBackground = true;
184 ProgressMonitorDialog dlg = getDialog();
185 if (dlg != null) {
186 reset();
187 dlg.setVisible(true);
188 }
189 };
190
191 private final WindowListener windowListener = new WindowAdapter() {
192 @Override public void windowClosing(WindowEvent e) {
193 cancel();
194 }
195 };
196
197 /**
198 * See if this task is canceleable
199 * @return <code>true</code> if it can be canceled
200 */
201 public final boolean isCancelable() {
202 return cancelable;
203 }
204
205 /**
206 * Sets this task to be cancelable
207 * @param cancelable Whether it can be canceled
208 */
209 public final void setCancelable(boolean cancelable) {
210 this.cancelable = cancelable;
211 }
212
213 @Override
214 public void doBeginTask() {
215 doInEDT(() -> {
216 Main.currentProgressMonitor = this;
217 if (GraphicsEnvironment.isHeadless()) {
218 return;
219 }
220 if (dialogParent != null && dialog == null) {
221 dialog = new PleaseWaitDialog(dialogParent);
222 } else {
223 throw new ProgressException("PleaseWaitDialog parent must be set");
224 }
225
226 if (windowTitle != null) {
227 dialog.setTitle(windowTitle);
228 }
229 dialog.setCancelEnabled(cancelable);
230 dialog.setCancelCallback(cancelListener);
231 dialog.setInBackgroundCallback(inBackgroundListener);
232 dialog.setCustomText("");
233 dialog.addWindowListener(windowListener);
234 dialog.setMaximumProgress(PROGRESS_BAR_MAX);
235 dialog.setVisible(true);
236 });
237 }
238
239 @Override
240 public void doFinishTask() {
241 // do nothing
242 }
243
244 @Override
245 protected void updateProgress(double progressValue) {
246 final int newValue = (int) (progressValue * PROGRESS_BAR_MAX);
247 if (newValue != currentProgressValue) {
248 currentProgressValue = newValue;
249 doInEDT(() -> {
250 ProgressMonitorDialog dlg = getDialog();
251 if (dlg != null) {
252 dlg.updateProgress(currentProgressValue);
253 }
254 });
255 }
256 }
257
258 @Override
259 protected void doSetCustomText(final String title) {
260 checkState(State.IN_TASK, State.IN_SUBTASK);
261 this.customText = title;
262 doInEDT(() -> {
263 ProgressMonitorDialog dlg = getDialog();
264 if (dlg != null) {
265 dlg.setCustomText(title);
266 }
267 });
268 }
269
270 @Override
271 protected void doSetTitle(final String title) {
272 checkState(State.IN_TASK, State.IN_SUBTASK);
273 this.title = title;
274 doInEDT(() -> {
275 ProgressMonitorDialog dlg = getDialog();
276 if (dlg != null) {
277 dlg.setCurrentAction(title);
278 }
279 });
280 }
281
282 @Override
283 protected void doSetIntermediate(final boolean value) {
284 this.indeterminate = value;
285 doInEDT(() -> {
286 // Enable only if progress is at the beginning. Doing intermediate progress in the middle
287 // will hide already reached progress
288 ProgressMonitorDialog dlg = getDialog();
289 if (dlg != null) {
290 dlg.setIndeterminate(value && currentProgressValue == 0);
291 }
292 });
293 }
294
295 @Override
296 public void appendLogMessage(final String message) {
297 doInEDT(() -> {
298 ProgressMonitorDialog dlg = getDialog();
299 if (dlg != null) {
300 dlg.appendLogMessage(message);
301 }
302 });
303 }
304
305 /**
306 * Update the dialog values
307 */
308 public void reset() {
309 if (dialog != null) {
310 dialog.setTitle(title);
311 dialog.setCustomText(customText);
312 dialog.updateProgress(currentProgressValue);
313 dialog.setIndeterminate(indeterminate && currentProgressValue == 0);
314 }
315 BackgroundProgressMonitor backgroundMonitor = null;
316 MapFrame map = Main.map;
317 if (map != null) {
318 backgroundMonitor = map.statusLine.progressMonitor;
319 }
320 if (backgroundMonitor != null) {
321 backgroundMonitor.setCurrentAction(title);
322 backgroundMonitor.setCustomText(customText);
323 backgroundMonitor.updateProgress(currentProgressValue);
324 backgroundMonitor.setIndeterminate(indeterminate && currentProgressValue == 0);
325 }
326 }
327
328 /**
329 * Close the progress dialog window.
330 */
331 public void close() {
332 doInEDT(() -> {
333 if (dialog != null) {
334 dialog.setVisible(false);
335 dialog.setCancelCallback(null);
336 dialog.setInBackgroundCallback(null);
337 dialog.removeWindowListener(windowListener);
338 dialog.dispose();
339 dialog = null;
340 Main.currentProgressMonitor = null;
341 MapFrame map = Main.map;
342 if (map != null) {
343 map.statusLine.progressMonitor.setVisible(false);
344 }
345 }
346 });
347 }
348
349 /**
350 * Show the progress dialog in foreground
351 */
352 public void showForegroundDialog() {
353 isInBackground = false;
354 doInEDT(() -> {
355 if (dialog != null) {
356 dialog.setInBackgroundPossible(taskId != null && Main.isDisplayingMapView());
357 reset();
358 getDialog();
359 }
360 });
361 }
362
363 @Override
364 public void setProgressTaskId(ProgressTaskId taskId) {
365 this.taskId = taskId;
366 doInEDT(() -> {
367 if (dialog != null) {
368 dialog.setInBackgroundPossible(taskId != null && Main.isDisplayingMapView());
369 }
370 });
371 }
372
373 @Override
374 public ProgressTaskId getProgressTaskId() {
375 return taskId;
376 }
377
378 @Override
379 public Component getWindowParent() {
380 Component parent = dialog;
381 if (isInBackground || parent == null)
382 return Main.parent;
383 else
384 return parent;
385 }
386
387 @Override
388 public String toString() {
389 return "PleaseWaitProgressMonitor [currentProgressValue=" + currentProgressValue + ", customText=" + customText
390 + ", title=" + title + ", indeterminate=" + indeterminate + ", isInBackground=" + isInBackground
391 + ", windowTitle=" + windowTitle + ", taskId=" + taskId + ", cancelable=" + cancelable + ", state="
392 + state + "]";
393 }
394}
Note: See TracBrowser for help on using the repository browser.