package net.sf.openrocket.gui.dialogs; import java.awt.Desktop; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.List; import java.util.Locale; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.communication.BugReporter; import net.sf.openrocket.gui.components.SelectableLabel; import net.sf.openrocket.gui.components.StyledLabel; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.LogLevelBufferLogger; import net.sf.openrocket.logging.LogLine; import net.sf.openrocket.logging.LoggingSystemSetup; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.BuildProperties; import net.sf.openrocket.util.JarUtil; import com.jogamp.opengl.JoglVersion; public class BugReportDialog extends JDialog { private static final String REPORT_EMAIL = "openrocket-bugs@lists.sourceforge.net"; private static final Translator trans = Application.getTranslator(); public BugReportDialog(Window parent, String labelText, final String message, final boolean sendIfUnchanged) { //// Bug report super(parent, trans.get("bugreport.dlg.title"), Dialog.ModalityType.APPLICATION_MODAL); JPanel panel = new JPanel(new MigLayout("fill")); // Some fscking Swing bug that makes html labels initially way too high JLabel label = new JLabel(labelText); Dimension d = label.getPreferredSize(); d.width = 100000; label.setMaximumSize(d); panel.add(label, "gapleft para, wrap para"); //// <html>If connected to the Internet, you can simply click //// <em>Send bug report</em>. label = new JLabel(trans.get("bugreport.dlg.connectedInternet")); d = label.getPreferredSize(); d.width = 100000; label.setMaximumSize(d); panel.add(label, "gapleft para, wrap"); //// Otherwise, send the text below to the address: panel.add(new JLabel(trans.get("bugreport.dlg.otherwise") + " "), "gapleft para, split 2, gapright rel"); panel.add(new SelectableLabel(REPORT_EMAIL), "growx, wrap para"); final JTextArea textArea = new JTextArea(message, 20, 70); textArea.setEditable(true); panel.add(new JScrollPane(textArea), "grow, wrap"); panel.add(new StyledLabel(trans.get("bugreport.lbl.Theinformation"), -1), "wrap para"); ////Close button JButton close = new JButton(trans.get("dlg.but.close")); close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { BugReportDialog.this.dispose(); } }); panel.add(close, "right, sizegroup buttons, split"); //// Mail button // if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Action.MAIL)) { // JButton mail = new JButton("Open email"); // mail.setToolTipText("Open email client with the suitable email ready."); // mail.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // String text = textArea.getText(); // openEmail(text); // } // }); // panel.add(mail, "right, sizegroup buttons"); // } //// Send bug report button JButton send = new JButton(trans.get("bugreport.dlg.but.Sendbugreport")); //// Automatically send the bug report to the OpenRocket developers. send.setToolTipText(trans.get("bugreport.dlg.but.Sendbugreport.Ttip")); send.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String text = textArea.getText(); if (text.equals(message) && !sendIfUnchanged) { JOptionPane.showMessageDialog(BugReportDialog.this, trans.get("bugreport.dlg.provideDescription"), trans.get("bugreport.dlg.provideDescription.title"), JOptionPane.ERROR_MESSAGE); return; } try { BugReporter.sendBugReport(text); // Success if we came here //bugreport.dlg.successmsg /*JOptionPane.showMessageDialog(BugReportDialog.this, new Object[] { "Bug report successfully sent.", "Thank you for helping make OpenRocket better!" }, "Bug report sent", JOptionPane.INFORMATION_MESSAGE);*/ JOptionPane.showMessageDialog(BugReportDialog.this, new Object[] { trans.get("bugreport.dlg.successmsg1"), trans.get("bugreport.dlg.successmsg2") }, trans.get("bugreport.dlg.successmsg3"), JOptionPane.INFORMATION_MESSAGE); } catch (Exception ex) { // Sending the message failed. JOptionPane.showMessageDialog(BugReportDialog.this, //// OpenRocket was unable to send the bug report: new Object[] { trans.get("bugreport.dlg.failedmsg1"), ex.getClass().getSimpleName() + ": " + ex.getMessage(), " ", //// Please send the report manually to trans.get("bugreport.dlg.failedmsg2") + " " + REPORT_EMAIL }, //// Error sending report trans.get("bugreport.dlg.failedmsg3"), JOptionPane.ERROR_MESSAGE); } } }); panel.add(send, "right, sizegroup buttons"); this.add(panel); this.validate(); this.pack(); this.pack(); this.setLocationRelativeTo(parent); GUIUtil.setDisposableDialogOptions(this, send); } /** * Show a general bug report dialog allowing the user to input information about * the bug they encountered. * * @param parent the parent window (may be null). */ public static void showBugReportDialog(Window parent) { StringBuilder sb = new StringBuilder(); sb.append("---------- Bug report ----------\n"); sb.append('\n'); sb.append("Include detailed steps on how to trigger the bug:\n"); sb.append('\n'); sb.append("1. \n"); sb.append("2. \n"); sb.append("3. \n"); sb.append('\n'); sb.append("What does the software do and what in your opinion should it do in the " + "case described above:\n"); sb.append('\n'); sb.append('\n'); sb.append('\n'); sb.append("Include your email address (optional; it helps if we can " + "contact you in case we need additional information):\n"); sb.append('\n'); sb.append('\n'); sb.append('\n'); sb.append("(Do not modify anything below this line.)\n"); sb.append("---------- System information ----------\n"); addSystemInformation(sb); sb.append("---------- Error log ----------\n"); addErrorLog(sb); sb.append("---------- End of bug report ----------\n"); sb.append('\n'); BugReportDialog reportDialog = new BugReportDialog(parent, trans.get("bugreport.reportDialog.txt"), sb.toString(), false); reportDialog.setVisible(true); } /** * Show a dialog presented when an uncaught exception occurs. * * @param parent the parent window (may be null). * @param t the thread that encountered the exception (may be null). * @param e the exception. */ public static void showExceptionDialog(Window parent, Thread t, Throwable e) { StringBuilder sb = new StringBuilder(); sb.append("---------- Bug report ----------\n"); sb.append('\n'); sb.append("Please include a description about what actions you were " + "performing when the exception occurred:\n"); sb.append('\n'); sb.append('\n'); sb.append('\n'); sb.append('\n'); sb.append("Include your email address (optional; it helps if we can " + "contact you in case we need additional information):\n"); sb.append('\n'); sb.append('\n'); sb.append('\n'); sb.append('\n'); sb.append("(Do not modify anything below this line.)\n"); sb.append("---------- Exception stack trace ----------\n"); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); sb.append(sw.getBuffer()); sb.append('\n'); sb.append("---------- Thread information ----------\n"); if (t == null) { sb.append("Thread is not specified."); } else { sb.append(t + "\n"); } sb.append('\n'); sb.append("---------- System information ----------\n"); addSystemInformation(sb); sb.append("---------- Error log ----------\n"); addErrorLog(sb); sb.append("---------- End of bug report ----------\n"); sb.append('\n'); BugReportDialog reportDialog = //// <html><b>Please include a short description about what you were doing when the exception occurred.</b> new BugReportDialog(parent, trans.get("bugreport.reportDialog.txt2"), sb.toString(), true); reportDialog.setVisible(true); } private static void addSystemInformation(StringBuilder sb) { sb.append("OpenRocket version: " + BuildProperties.getVersion() + "\n"); sb.append("OpenRocket source: " + BuildProperties.getBuildSource() + "\n"); sb.append("OpenRocket location: " + JarUtil.getCurrentJarFile() + "\n"); sb.append("JOGL version: " + JoglVersion.getInstance().getImplementationVersion() + "\n"); sb.append("Current default locale: " + Locale.getDefault() + "\n"); sb.append("System properties:\n"); // Sort the keys SortedSet<String> keys = new TreeSet<String>(); for (Object key : System.getProperties().keySet()) { keys.add((String) key); } for (String key : keys) { String value = System.getProperty(key); sb.append(" " + key + "="); if (key.equals("line.separator")) { for (char c : value.toCharArray()) { sb.append(String.format("\\u%04x", (int) c)); } } else { sb.append(value); } sb.append('\n'); } } private static void addErrorLog(StringBuilder sb) { LogLevelBufferLogger buffer = LoggingSystemSetup.getBufferLogger(); List<LogLine> logs = buffer.getLogs(); for (LogLine l : logs) { sb.append(l.toString()).append('\n'); } } /** * Open the default email client with the suitable bug report. * Note that this does not work on some systems even if Desktop.isSupported() * claims so. * * @param text the bug report text. * @return whether opening the client succeeded. */ @SuppressWarnings("unused") private boolean openEmail(String text) { String version; try { text = URLEncoder.encode(text, "UTF-8"); version = URLEncoder.encode(BuildProperties.getVersion(), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new BugException(e); } String mailto = "mailto:" + REPORT_EMAIL + "?subject=Bug%20report%20for%20OpenRocket%20" + version + "?body=" + text; URI uri; try { uri = new URI(mailto); } catch (URISyntaxException e) { e.printStackTrace(); return false; } Desktop desktop = Desktop.getDesktop(); try { desktop.mail(uri); } catch (IOException e) { e.printStackTrace(); return false; } return true; } }