updates for 0.9.3
[debian/openrocket] / src / net / sf / openrocket / gui / dialogs / BugReportDialog.java
1 package net.sf.openrocket.gui.dialogs;
2
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;
15 import java.net.URI;
16 import java.net.URISyntaxException;
17 import java.net.URL;
18 import java.net.URLEncoder;
19 import java.util.SortedSet;
20 import java.util.TreeSet;
21
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;
29
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;
36
37 public class BugReportDialog extends JDialog {
38         
39         private static final String REPORT_EMAIL = "openrocket-bugs@lists.sourceforge.net";
40         
41         private static final String REPORT_URL = 
42                 "http://openrocket.sourceforge.net/actions/reportbug";
43
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
48         
49
50         public BugReportDialog(Window parent, String labelText, String message) {
51                 super(parent, "Bug report", Dialog.ModalityType.APPLICATION_MODAL);
52                 
53                 JPanel panel = new JPanel(new MigLayout("fill"));
54                 
55                 // Some fscking Swing bug that makes html labels initially way too high
56                 JLabel label = new JLabel(labelText);
57                 Dimension d = label.getPreferredSize();
58                 d.width = 100000;
59                 label.setMaximumSize(d);
60                 panel.add(label, "gapleft para, wrap para");
61
62                 label = new JLabel("<html>If connected to the Internet, you can simply click " +
63                 "<em>Send bug report</em>.");
64                 d = label.getPreferredSize();
65                 d.width = 100000;
66                 label.setMaximumSize(d);
67                 panel.add(label, "gapleft para, wrap");
68                 
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");
72                 
73
74                 final JTextArea textArea = new JTextArea(message, 20, 70);
75                 textArea.setEditable(true);
76                 panel.add(new JScrollPane(textArea), "grow, wrap");
77                 
78                 
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");
82                 
83                 
84                 
85                 ////  Close button
86                 JButton close = new JButton("Close");
87                 close.addActionListener(new ActionListener() {
88                         @Override
89                         public void actionPerformed(ActionEvent e) {
90                                 BugReportDialog.this.dispose();
91                         }
92                 });
93                 panel.add(close, "right, sizegroup buttons, split");
94                 
95                 
96                 ////  Mail button
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() {
101 //                              @Override
102 //                              public void actionPerformed(ActionEvent e) {
103 //                                      String text = textArea.getText();
104 //                                      openEmail(text);
105 //                              }
106 //                      });
107 //                      panel.add(mail, "right, sizegroup buttons");
108 //              }
109                 
110                 
111                 ////  Send button
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() {
115                         @Override
116                         public void actionPerformed(ActionEvent e) {
117                                 String text = textArea.getText();
118                                 try {
119                                         
120                                         sendReport(text);
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);
126                                         
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);
134                                 }
135                         }
136                 });
137                 panel.add(send, "right, sizegroup buttons");
138                 
139                 this.add(panel);
140                 
141                 this.validate();
142                 this.pack();
143                 this.pack();
144                 this.setLocationRelativeTo(parent);
145                 GUIUtil.installEscapeCloseOperation(this);
146 //              GUIUtil.setDefaultButton(close);
147         }
148
149         
150         
151         /**
152          * Show a general bug report dialog allowing the user to input information about
153          * the bug they encountered.
154          * 
155          * @param parent        the parent window (may be null).
156          */
157         public static void showBugReportDialog(Window parent) {
158
159                 StringBuilder sb = new StringBuilder();
160                 
161                 sb.append("---------- Bug report ----------\n");
162                 sb.append('\n');
163                 sb.append("Include detailed steps on how to trigger the bug:\n");
164                 sb.append('\n');
165                 sb.append("1. \n");
166                 sb.append("2. \n");
167                 sb.append("3. \n");
168                 sb.append('\n');
169                 
170                 sb.append("What does the software do and what in your opinion should it do in the " +
171                                 "case described above:\n");
172                 sb.append('\n');
173                 sb.append('\n');
174                 sb.append('\n');
175                 
176                 sb.append("Include your email address (optional; it helps if we can " +
177                 "contact you in case we need additional information):\n");
178                 sb.append('\n');
179                 sb.append('\n');
180                 sb.append('\n');
181                 
182
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");
187                 sb.append('\n');
188                 
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);
196         }
197         
198         
199         /**
200          * Show a dialog presented when an uncaught exception occurs.
201          * 
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.
205          */
206         public static void showExceptionDialog(Window parent, Thread t, Throwable e) {
207
208                 StringBuilder sb = new StringBuilder();
209                 
210                 sb.append("---------- Bug report ----------\n");
211                 sb.append('\n');
212                 sb.append("Please include a description about what actions you were " +
213                                 "performing when the exception occurred:\n");
214                 sb.append('\n');
215                 sb.append('\n');
216                 sb.append('\n');
217                 sb.append('\n');
218                 
219
220                 sb.append("Include your email address (optional; it helps if we can " +
221                                 "contact you in case we need additional information):\n");
222                 sb.append('\n');
223                 sb.append('\n');
224                 sb.append('\n');
225                 sb.append('\n');
226
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());
233                 sb.append('\n');
234                 
235                 
236                 sb.append("---------- Thread information ----------\n");
237                 if (t == null) {
238                         sb.append("Thread is not specified.");
239                 } else {
240                         sb.append(t + "\n");
241                 }
242                 sb.append('\n');
243                 
244                 
245                 sb.append("---------- System information ----------\n");
246                 addSystemInformation(sb);
247                 sb.append("---------- End of information ----------\n");
248                 sb.append('\n');
249                 
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);
254         }
255         
256         
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");
262
263                 // Sort the keys
264                 SortedSet<String> keys = new TreeSet<String>();
265                 for (Object key: System.getProperties().keySet()) {
266                         keys.add((String)key);
267                 }
268                 
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));
275                                 }
276                         } else {
277                                 sb.append(value);
278                         }
279                         sb.append('\n');
280                 }
281         }
282         
283         
284         
285         /**
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.
289          * 
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.
293          */
294         private void sendReport(String report) throws IOException {
295                 URL url = new URL(REPORT_URL);
296                 
297                 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
298                 
299                 connection.setConnectTimeout(REPORT_TIMEOUT);
300                 connection.setInstanceFollowRedirects(true);
301                 connection.setRequestMethod("POST");
302                 connection.setUseCaches(false);
303                 
304                 String post;
305                 post = (REPORT_VERSION_PARAM + "=" + URLEncoder.encode(Prefs.getVersion(), "UTF-8")
306                                 + "&" + REPORT_PARAM + "=" + URLEncoder.encode(report, "UTF-8"));
307                 
308                 OutputStreamWriter wr = null;
309                 try {
310                         // Send post information
311                         connection.setDoOutput(true);
312                         wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
313                         wr.write(post);
314                         wr.flush();
315                         
316                         if (connection.getResponseCode() != REPORT_RESPONSE_CODE) {
317                                 throw new IOException("Server responded with code " + 
318                                                 connection.getResponseCode() + ", expecting " + REPORT_RESPONSE_CODE);
319                         }
320                 } finally {
321                         if (wr != null)
322                                 wr.close();
323                         connection.disconnect();
324                 }
325         }
326         
327
328         /**
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()
331          * claims so.
332          * 
333          * @param text  the bug report text.
334          * @return              whether opening the client succeeded.
335          */
336         private boolean openEmail(String text) {
337                 String version;
338                 
339                 try {
340                         text = URLEncoder.encode(text, "UTF-8");
341                         version = URLEncoder.encode(Prefs.getVersion(), "UTF-8");
342                 } catch (UnsupportedEncodingException e) {
343                         throw new RuntimeException(e);
344                 }
345                 
346                 
347                 
348                 String mailto = "mailto:" + REPORT_EMAIL
349                         + "?subject=Bug%20report%20for%20OpenRocket%20" + version 
350                         + "?body=" + text;
351                 URI uri;
352                 try {
353                         uri = new URI(mailto);
354                 } catch (URISyntaxException e) {
355                         e.printStackTrace();
356                         return false;
357                 }
358                 
359                 Desktop desktop = Desktop.getDesktop();
360                 try {
361                         desktop.mail(uri);
362                 } catch (IOException e) {
363                         e.printStackTrace();
364                         return false;
365                 }
366                 
367                 return true;
368         }
369         
370 }