1 package net.sf.openrocket.gui.dialogs;
3 import java.awt.Desktop;
4 import java.awt.Dialog;
5 import java.awt.Dimension;
6 import java.awt.Window;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.io.IOException;
10 import java.io.OutputStreamWriter;
11 import java.io.PrintWriter;
12 import java.io.StringWriter;
13 import java.io.UnsupportedEncodingException;
14 import java.net.HttpURLConnection;
16 import java.net.URISyntaxException;
18 import java.net.URLEncoder;
19 import java.util.SortedSet;
20 import java.util.TreeSet;
22 import javax.swing.JButton;
23 import javax.swing.JDialog;
24 import javax.swing.JLabel;
25 import javax.swing.JOptionPane;
26 import javax.swing.JPanel;
27 import javax.swing.JScrollPane;
28 import javax.swing.JTextArea;
30 import net.miginfocom.swing.MigLayout;
31 import net.sf.openrocket.gui.components.ResizeLabel;
32 import net.sf.openrocket.gui.components.SelectableLabel;
33 import net.sf.openrocket.util.GUIUtil;
34 import net.sf.openrocket.util.JarUtil;
35 import net.sf.openrocket.util.Prefs;
37 public class BugReportDialog extends JDialog {
39 private static final String REPORT_EMAIL = "openrocket-bugs@lists.sourceforge.net";
41 private static final String REPORT_URL =
42 "http://openrocket.sourceforge.net/actions/reportbug";
44 private static final String REPORT_VERSION_PARAM = "version";
45 private static final String REPORT_PARAM = "content";
46 private static final int REPORT_RESPONSE_CODE = HttpURLConnection.HTTP_CREATED;
47 private static final int REPORT_TIMEOUT = 10000; // in milliseconds
50 public BugReportDialog(Window parent, String labelText, String message) {
51 super(parent, "Bug report", Dialog.ModalityType.APPLICATION_MODAL);
53 JPanel panel = new JPanel(new MigLayout("fill"));
55 // Some fscking Swing bug that makes html labels initially way too high
56 JLabel label = new JLabel(labelText);
57 Dimension d = label.getPreferredSize();
59 label.setMaximumSize(d);
60 panel.add(label, "gapleft para, wrap para");
62 label = new JLabel("<html>If connected to the Internet, you can simply click " +
63 "<em>Send bug report</em>.");
64 d = label.getPreferredSize();
66 label.setMaximumSize(d);
67 panel.add(label, "gapleft para, wrap");
69 panel.add(new JLabel("Otherwise, send the text below to the address: "),
70 "gapleft para, split 2, gapright rel");
71 panel.add(new SelectableLabel(REPORT_EMAIL), "growx, wrap para");
74 final JTextArea textArea = new JTextArea(message, 20, 70);
75 textArea.setEditable(true);
76 panel.add(new JScrollPane(textArea), "grow, wrap");
79 panel.add(new ResizeLabel("The information above may be included in a public " +
80 "bug report. Make sure it does not contain any sensitive information you " +
81 "do not want to be made public.", -1), "wrap para");
86 JButton close = new JButton("Close");
87 close.addActionListener(new ActionListener() {
89 public void actionPerformed(ActionEvent e) {
90 BugReportDialog.this.dispose();
93 panel.add(close, "right, sizegroup buttons, split");
97 // if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Action.MAIL)) {
98 // JButton mail = new JButton("Open email");
99 // mail.setToolTipText("Open email client with the suitable email ready.");
100 // mail.addActionListener(new ActionListener() {
102 // public void actionPerformed(ActionEvent e) {
103 // String text = textArea.getText();
107 // panel.add(mail, "right, sizegroup buttons");
112 JButton send = new JButton("Send bug report");
113 send.setToolTipText("Automatically send the bug report to the OpenRocket developers.");
114 send.addActionListener(new ActionListener() {
116 public void actionPerformed(ActionEvent e) {
117 String text = textArea.getText();
121 // Success if we came here
122 JOptionPane.showMessageDialog(BugReportDialog.this,
123 new Object[] { "Bug report successfully sent.",
124 "Thank you for helping make OpenRocket better!" },
125 "Bug report sent", JOptionPane.INFORMATION_MESSAGE);
127 } catch (Exception ex) {
128 // Sending the message failed.
129 JOptionPane.showMessageDialog(BugReportDialog.this,
130 new Object[] { "OpenRocket was unable to send the bug report:",
131 ex.getClass().getSimpleName() + ": " + ex.getMessage(), " ",
132 "Please send the report manually to " + REPORT_EMAIL },
133 "Error sending report", JOptionPane.ERROR_MESSAGE);
137 panel.add(send, "right, sizegroup buttons");
144 this.setLocationRelativeTo(parent);
145 GUIUtil.installEscapeCloseOperation(this);
146 // GUIUtil.setDefaultButton(close);
152 * Show a general bug report dialog allowing the user to input information about
153 * the bug they encountered.
155 * @param parent the parent window (may be null).
157 public static void showBugReportDialog(Window parent) {
159 StringBuilder sb = new StringBuilder();
161 sb.append("---------- Bug report ----------\n");
163 sb.append("Include detailed steps on how to trigger the bug:\n");
170 sb.append("What does the software do and what in your opinion should it do in the " +
171 "case described above:\n");
176 sb.append("Include your email address (optional; it helps if we can " +
177 "contact you in case we need additional information):\n");
183 sb.append("(Do not modify anything below this line.)\n");
184 sb.append("---------- System information ----------\n");
185 addSystemInformation(sb);
186 sb.append("---------- End of information ----------\n");
189 BugReportDialog reportDialog =
190 new BugReportDialog(parent,
191 "<html>You can report a bug in OpenRocket by filling in and submitting " +
192 "the form below.<br>" +
193 "You can also report bugs and include attachments on the project " +
194 "web site.", sb.toString());
195 reportDialog.setVisible(true);
200 * Show a dialog presented when an uncaught exception occurs.
202 * @param parent the parent window (may be null).
203 * @param t the thread that encountered the exception (may be null).
204 * @param e the exception.
206 public static void showExceptionDialog(Window parent, Thread t, Throwable e) {
208 StringBuilder sb = new StringBuilder();
210 sb.append("---------- Bug report ----------\n");
212 sb.append("Please include a description about what actions you were " +
213 "performing when the exception occurred:\n");
220 sb.append("Include your email address (optional; it helps if we can " +
221 "contact you in case we need additional information):\n");
227 sb.append("(Do not modify anything below this line.)\n");
228 sb.append("---------- Exception stack trace ----------\n");
229 StringWriter sw = new StringWriter();
230 PrintWriter pw = new PrintWriter(sw);
231 e.printStackTrace(pw);
232 sb.append(sw.getBuffer());
236 sb.append("---------- Thread information ----------\n");
238 sb.append("Thread is not specified.");
245 sb.append("---------- System information ----------\n");
246 addSystemInformation(sb);
247 sb.append("---------- End of information ----------\n");
250 BugReportDialog reportDialog =
251 new BugReportDialog(parent, "Please include a short description about " +
252 "what you were doing when the exception occurred.", sb.toString());
253 reportDialog.setVisible(true);
257 private static void addSystemInformation(StringBuilder sb) {
258 sb.append("OpenRocket version: " + Prefs.getVersion() + "\n");
259 sb.append("OpenRocket source: " + Prefs.getBuildSource() + "\n");
260 sb.append("OpenRocket location: " + JarUtil.getCurrentJarFile() + "\n");
261 sb.append("System properties:\n");
264 SortedSet<String> keys = new TreeSet<String>();
265 for (Object key: System.getProperties().keySet()) {
266 keys.add((String)key);
269 for (String key: keys) {
270 String value = System.getProperty(key);
271 sb.append(" " + key + "=");
272 if (key.equals("line.separator")) {
273 for (char c: value.toCharArray()) {
274 sb.append(String.format("\\u%04x", (int)c));
286 * Send the provided report to the OpenRocket bug report URL. If the connection
287 * fails or the server does not respond with the correct response code, an
288 * exception is thrown.
290 * @param report the report to send.
291 * @throws IOException if an error occurs while connecting to the server or
292 * the server responds with a wrong response code.
294 private void sendReport(String report) throws IOException {
295 URL url = new URL(REPORT_URL);
297 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
299 connection.setConnectTimeout(REPORT_TIMEOUT);
300 connection.setInstanceFollowRedirects(true);
301 connection.setRequestMethod("POST");
302 connection.setUseCaches(false);
305 post = (REPORT_VERSION_PARAM + "=" + URLEncoder.encode(Prefs.getVersion(), "UTF-8")
306 + "&" + REPORT_PARAM + "=" + URLEncoder.encode(report, "UTF-8"));
308 OutputStreamWriter wr = null;
310 // Send post information
311 connection.setDoOutput(true);
312 wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
316 if (connection.getResponseCode() != REPORT_RESPONSE_CODE) {
317 throw new IOException("Server responded with code " +
318 connection.getResponseCode() + ", expecting " + REPORT_RESPONSE_CODE);
323 connection.disconnect();
329 * Open the default email client with the suitable bug report.
330 * Note that this does not work on some systems even if Desktop.isSupported()
333 * @param text the bug report text.
334 * @return whether opening the client succeeded.
336 private boolean openEmail(String text) {
340 text = URLEncoder.encode(text, "UTF-8");
341 version = URLEncoder.encode(Prefs.getVersion(), "UTF-8");
342 } catch (UnsupportedEncodingException e) {
343 throw new RuntimeException(e);
348 String mailto = "mailto:" + REPORT_EMAIL
349 + "?subject=Bug%20report%20for%20OpenRocket%20" + version
353 uri = new URI(mailto);
354 } catch (URISyntaxException e) {
359 Desktop desktop = Desktop.getDesktop();
362 } catch (IOException e) {