View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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      //--- Constant(s) ---
60  
61      //--- Data field(s) ---
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      //--- Constructor(s) ---
82  
83      public ErrorDialog(String description) 
84      {
85  		super(BUTTON_NONE);
86  
87  		// top
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  		// details, instantiate prior to action
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 		// top buttons
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 		// check boxes
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 		// dialog
138 		setTitle(XNap.tr("XNap Error"));
139 		pack();
140 		setSize(prefs.getInt("errorDialogWidth"), 
141 				prefs.getInt("errorDialogHeight"));
142     }
143 
144     //--- Method(s) ---
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 // 		jtaDetails.append("Thread: " + t.getName() + "\n");
156 		
157 // 		jtaDetails.append("Loaded jars:\n");
158 // 		URL[] urls = XNapClassLoader.getInstance().getURLs(); 
159 // 		for (int i=0; i < urls.length; i++) {
160 // 			jtaDetails.append(urls[i].toString()+"\n"); 
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 	/*	public static String printStackTrace(Throwable t) {
174 		StringBuffer sb = new StringBuffer(t.toString());
175 		StackTraceElement[] trace = t.getStackTrace();
176 		for (int i = 0; i < trace.length; i++) {
177 			sb.append("\tat " + trace[i]);
178 		}
179 		
180 		Throwable ourCause = get // to be continued or not...
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 	//--- Inner Class(es) ---
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