1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui;
21
22 import java.awt.Component;
23 import java.awt.FlowLayout;
24 import java.awt.Font;
25 import java.awt.GridBagLayout;
26 import java.awt.event.ActionEvent;
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 import java.io.PrintWriter;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32
33 import javax.swing.AbstractAction;
34 import javax.swing.Action;
35 import javax.swing.JCheckBox;
36 import javax.swing.JLabel;
37 import javax.swing.JOptionPane;
38 import javax.swing.JPanel;
39 import javax.swing.JScrollPane;
40 import javax.swing.JTextArea;
41 import javax.swing.SwingUtilities;
42
43 import org.xnap.XNap;
44 import org.xnap.action.AbstractToggleAction;
45 import org.xnap.gui.component.DefaultDialog;
46 import org.xnap.gui.component.MultiLineLabel;
47 import org.xnap.gui.component.XNapButton;
48 import org.xnap.gui.component.XNapToggleButton;
49 import org.xnap.gui.util.GUIHelper;
50 import org.xnap.gui.util.GridBagHelper;
51 import org.xnap.gui.util.IconHelper;
52 import org.xnap.net.NetHelper;
53 import org.xnap.util.Preferences;
54 import org.xnap.util.UncaughtExceptionManager;
55
56 public class ErrorDialog extends DefaultDialog
57 {
58
59
60
61
62
63 private static Preferences prefs = Preferences.getInstance();
64
65 private JPanel jpDetails;
66 private JTextArea jtaDetails;
67
68 private JCheckBox jcbDoNotShowExceptionAgain;
69 private JCheckBox jcbDoNotShowDialogAgain;
70
71 private SendAction acSend = new SendAction();
72
73 private LinkedList threads = new LinkedList();
74 private LinkedList throwables = new LinkedList();
75
76 /***
77 * If true, the dialog can not handle more exceptions.
78 */
79 private boolean busy = false;
80
81
82
83 public ErrorDialog(String description)
84 {
85 super(BUTTON_NONE);
86
87
88 JPanel jpMain = getMainPanel();
89 jpMain.setLayout(new GridBagLayout());
90
91 description += "\n\n" + XNap.tr("Feel free to press <Show Details> and send the bug report below. The report will be publicly visible at http://xnap.sf.net/report/.\n\nPlease note that you still have to file a proper bug report at http://bugs.xnap.org if you want to get the problem fixed.");
92
93 MultiLineLabel jlInfo = new MultiLineLabel(description);
94 jlInfo.setColumns(40);
95 GridBagHelper.addComponent
96 (jpMain, new JLabel(IconHelper.getIcon("error.png", 32)));
97 GridBagHelper.add(jpMain, jlInfo);
98
99
100 jpDetails = new JPanel(new GridBagLayout());
101 updateBorder();
102
103 jtaDetails = new JTextArea(10, 60);
104 jtaDetails.setEditable (false);
105 jtaDetails.setFont(new Font("Monospaced", Font.PLAIN, 10));
106 GridBagHelper.addPanel(jpDetails, new JScrollPane(jtaDetails));
107
108 GridBagHelper.addComponent(jpDetails, new XNapButton(acSend));
109
110
111 JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.RIGHT));
112 GridBagHelper.add(jpMain, jpButtons);
113
114 jpButtons.add(new XNapToggleButton(new DetailsAction()));
115
116 GridBagHelper.addPanel(jpMain, jpDetails);
117
118 jtaDetails.append(FeedbackWizardDialog.getSystemInfo(false) + "\n");
119 jtaDetails.setCaretPosition(0);
120
121
122 jcbDoNotShowExceptionAgain
123 = new JCheckBox(XNap.tr("Do not show this exception again"),
124 !XNap.isRunFromCvs());
125 GridBagHelper.add(jpMain, jcbDoNotShowExceptionAgain);
126
127 jcbDoNotShowDialogAgain
128 = new JCheckBox(XNap.tr("Do not show this dialog again"),
129 false);
130 GridBagHelper.add(jpMain, jcbDoNotShowDialogAgain);
131
132 Action continueAction = new ContinueAction();
133 GUIHelper.bindEscapeKey(getTopPanel(), continueAction);
134 getButtonPanel().add(new XNapButton(continueAction));
135 getButtonPanel().add(new XNapButton(new ExitAction()));
136
137
138 setTitle(XNap.tr("XNap Error"));
139 pack();
140 setSize(prefs.getInt("errorDialogWidth"),
141 prefs.getInt("errorDialogHeight"));
142 }
143
144
145
146 public void add(Thread t, Throwable e)
147 {
148 threads.add(t);
149 throwables.add(e);
150
151 ByteArrayOutputStream out = new ByteArrayOutputStream();
152 PrintWriter writer = new PrintWriter(out);
153 e.printStackTrace(writer);
154 writer.close();
155
156
157
158
159
160
161
162
163 String pluginName = UncaughtExceptionManager.getPlugin(e);
164 if (pluginName != null) {
165 jtaDetails.append(XNap.tr("Plugin: {0}", pluginName) + "\n");
166 }
167
168 jtaDetails.append(out.toString() + "\n");
169
170 updateBorder();
171 }
172
173
174
175
176
177
178
179
180
181
182
183 public void close()
184 {
185 prefs.set("errorDialogWidth", getBounds().getSize().width);
186 prefs.set("errorDialogHeight", getBounds().getSize().height);
187 Dialogs.setShowDialog("Error", !jcbDoNotShowDialogAgain.isSelected());
188 prefs.set("errorDialogDetailsVisible", jpDetails.isVisible());
189
190 if (jcbDoNotShowExceptionAgain.isSelected()) {
191 for (Iterator i = throwables.iterator(); i.hasNext();) {
192 UncaughtExceptionManager.getInstance().dontNotifyAgain
193 ((Throwable)i.next());
194 }
195 }
196
197 busy = true;
198 dispose();
199 }
200
201 public boolean isBusy()
202 {
203 return busy;
204 }
205
206 public void updateBorder()
207 {
208 jpDetails.setBorder
209 (GUIHelper.createDefaultBorder
210 (XNap.tr("Details") + " - "
211 + XNap.tr("{0} Problems", new Integer(threads.size()))));
212 }
213
214 public static void show(Component c, String description,
215 Throwable e)
216 {
217 ErrorDialog d = new ErrorDialog(description);
218 d.setModal(true);
219 d.add(Thread.currentThread(), e);
220 d.show(d);
221 }
222
223
224
225 private class DetailsAction extends AbstractToggleAction
226 {
227 public DetailsAction()
228 {
229 super(prefs.getBoolean("errorDialogDetailsVisible"));
230
231 putValue(Action.NAME, XNap.tr("Show Details"));
232 putValue(IconHelper.XNAP_ICON, "2downarrow.png");
233 putValue(Action.SHORT_DESCRIPTION,
234 XNap.tr("Shows more information about the problem."));
235
236 toggled(isSelected());
237 }
238
239 public void toggled(boolean visible)
240 {
241 jpDetails.setVisible(visible);
242 pack();
243 }
244
245 }
246
247 private class ContinueAction extends AbstractAction
248 {
249 public ContinueAction()
250 {
251 putValue(Action.NAME, XNap.tr("Continue"));
252 putValue(IconHelper.XNAP_ICON, "1rightarrow.png");
253 putValue(Action.SHORT_DESCRIPTION,
254 XNap.tr("Tries to continue."));
255 }
256
257 public void actionPerformed(ActionEvent event)
258 {
259 close();
260 }
261
262 }
263
264 private class ExitAction extends AbstractAction
265 {
266 public ExitAction()
267 {
268 putValue(Action.NAME, XNap.tr("Quit XNap"));
269 putValue(IconHelper.XNAP_ICON, "exit.png");
270 putValue(Action.SHORT_DESCRIPTION,
271 XNap.tr("Quits the application."));
272 }
273
274 public void actionPerformed(ActionEvent event)
275 {
276 close();
277 System.exit(1);
278 }
279
280 }
281
282 private class SendAction extends AbstractAction
283 {
284 public SendAction()
285 {
286 putValue(Action.NAME, XNap.tr("Send Report"));
287 putValue(IconHelper.XNAP_ICON, "mail_send2.png");
288 putValue(Action.SHORT_DESCRIPTION,
289 XNap.tr("Sends the details to the XNap team for analyzation."));
290 }
291
292 public void actionPerformed(ActionEvent event)
293 {
294 busy = true;
295
296 Thread t = new Thread(new SendWorker(), "SendFeedback");
297 t.start();
298 }
299 }
300
301 private class SendWorker implements Runnable
302 {
303
304 public void run()
305 {
306 acSend.setEnabled(false);
307 getCancelAction().setEnabled(false);
308
309 setTitle(XNap.tr("Sending error report") + "...");
310
311 try {
312 Iterator i1 = threads.iterator();
313 Iterator i2 = throwables.iterator();
314 while (i1.hasNext() && i2.hasNext()) {
315 UncaughtExceptionManager.getInstance().sendProblemReport
316 ((Thread)i1.next(), (Throwable)i2.next());
317 }
318 }
319 catch(final IOException e) {
320 Runnable runner = new Runnable()
321 {
322 public void run()
323 {
324 failed(NetHelper.getErrorMessage(e));
325 }
326 };
327 SwingUtilities.invokeLater(runner);
328 return;
329 }
330
331 Runnable runner = new Runnable()
332 {
333 public void run()
334 {
335 JOptionPane.showMessageDialog
336 (ErrorDialog.this, XNap.tr("Thank you."),
337 XNap.tr("XNap Error"),
338 JOptionPane.INFORMATION_MESSAGE);
339 close();
340 }
341 };
342 SwingUtilities.invokeLater(runner);
343 }
344
345 public void failed(String response)
346 {
347 JOptionPane.showMessageDialog
348 (ErrorDialog.this,
349 XNap.tr("Could not send error report: {0}.", response),
350 XNap.tr("XNap Error"),
351 JOptionPane.ERROR_MESSAGE);
352
353 setTitle(XNap.tr("XNap Error"));
354
355 acSend.setEnabled(true);
356 getCancelAction().setEnabled(true);
357
358 busy = false;
359 }
360 }
361
362 }
363
364
365
366
367
368
369