source: josm/trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java@ 1493

Last change on this file since 1493 was 1493, checked in by stoecker, 15 years ago

fix #2309 - Exception might get lost when ExecutorService is used

  • Property svn:eol-style set to native
File size: 5.9 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.EventQueue;
7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener;
9import java.awt.event.WindowAdapter;
10import java.awt.event.WindowEvent;
11import java.io.FileNotFoundException;
12import java.io.IOException;
13import java.lang.reflect.InvocationTargetException;
14
15import javax.swing.JOptionPane;
16import javax.swing.SwingUtilities;
17
18import org.openstreetmap.josm.Main;
19import org.xml.sax.SAXException;
20
21/**
22 * Instanced of this thread will display a "Please Wait" message in middle of JOSM
23 * to indicate a progress being executed.
24 *
25 * @author Imi
26 */
27public abstract class PleaseWaitRunnable implements Runnable {
28 public boolean silent = false;
29 public String errorMessage;
30
31 private boolean closeDialogCalled = false;
32 private boolean cancelled = false;
33 private boolean ignoreException;
34
35 private final String title;
36
37 /**
38 * Create the runnable object with a given message for the user.
39 */
40 public PleaseWaitRunnable(String title) {
41 this(title, false);
42 }
43
44 /**
45 * Create the runnable object with a given message for the user.
46 * @param title Message for user
47 * @param ignoreException If true, exception will be propaged to calling code. If false then
48 * exception will be thrown directly in EDT. When this runnable is executed using executor framework
49 * then use false unless you read result of task (because exception will get lost if you don't)
50 */
51 public PleaseWaitRunnable(String title, boolean ignoreException) {
52 this.title = title;
53 this.ignoreException = ignoreException;
54 Main.pleaseWaitDlg.cancel.addActionListener(new ActionListener(){
55 public void actionPerformed(ActionEvent e) {
56 if (!cancelled) {
57 cancelled = true;
58 cancel();
59 }
60 }
61 });
62 Main.pleaseWaitDlg.addWindowListener(new WindowAdapter(){
63 @Override public void windowClosing(WindowEvent e) {
64 if (!closeDialogCalled) {
65 if (!cancelled) {
66 cancelled = true;
67 cancel();
68 }
69 closeDialog();
70 }
71 }
72 });
73 }
74
75 public final void run() {
76 try {
77 try {
78 if (cancelled)
79 return; // since realRun isn't executed, do not call to finish
80
81 // reset dialog state
82 Main.pleaseWaitDlg.setTitle(title);
83 Main.pleaseWaitDlg.cancel.setEnabled(true);
84 Main.pleaseWaitDlg.setCustomText("");
85 errorMessage = null;
86 closeDialogCalled = false;
87
88 // show the dialog
89 synchronized (this) {
90 EventQueue.invokeLater(new Runnable() {
91 public void run() {
92 synchronized (PleaseWaitRunnable.this) {
93 PleaseWaitRunnable.this.notifyAll();
94 }
95 Main.pleaseWaitDlg.setVisible(true);
96 }
97 });
98 try {wait();} catch (InterruptedException e) {}
99 }
100
101 realRun();
102 } catch (SAXException x) {
103 x.printStackTrace();
104 errorMessage = tr("Error while parsing")+": "+x.getMessage();
105 } catch (FileNotFoundException x) {
106 x.printStackTrace();
107 errorMessage = tr("File not found")+": "+x.getMessage();
108 } catch (IOException x) {
109 x.printStackTrace();
110 errorMessage = x.getMessage();
111 } finally {
112 closeDialog();
113 }
114 } catch (final Throwable e) {
115 if (!ignoreException) {
116 // Exception has to thrown in EDT to be shown to user
117 SwingUtilities.invokeLater(new Runnable() {
118 public void run() {
119 throw new RuntimeException(e);
120 }
121 });
122 }
123 }
124 }
125
126 /**
127 * User pressed cancel button.
128 */
129 protected abstract void cancel();
130
131 /**
132 * Called in the worker thread to do the actual work. When any of the
133 * exception is thrown, a message box will be displayed and closeDialog
134 * is called. finish() is called in any case.
135 */
136 protected abstract void realRun() throws SAXException, IOException;
137
138 /**
139 * Finish up the data work. Is guaranteed to be called if realRun is called.
140 * Finish is called in the gui thread just after the dialog disappeared.
141 */
142 protected abstract void finish();
143
144 /**
145 * Close the dialog. Usually called from worker thread.
146 */
147 public void closeDialog() {
148 if (closeDialogCalled)
149 return;
150 closeDialogCalled = true;
151 try {
152 Runnable runnable = new Runnable(){
153 public void run() {
154 try {
155 finish();
156 } finally {
157 Main.pleaseWaitDlg.setVisible(false);
158 Main.pleaseWaitDlg.dispose();
159 }
160 if (errorMessage != null && !silent)
161 JOptionPane.showMessageDialog(Main.parent, errorMessage);
162 }
163 };
164
165 // make sure, this is called in the dispatcher thread ASAP
166 if (EventQueue.isDispatchThread())
167 runnable.run();
168 else
169 EventQueue.invokeAndWait(runnable);
170
171 } catch (InterruptedException e) {
172 } catch (InvocationTargetException e) {
173 throw new RuntimeException(e);
174 }
175 }
176}
Note: See TracBrowser for help on using the repository browser.