source: josm/trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportDialog.java@ 13661

Last change on this file since 13661 was 13647, checked in by Don-vip, 6 years ago

see #16204 - Allow to start and close JOSM in WebStart sandbox mode (where every external access is denied). This was very useful to reproduce some very tricky bugs that occured in real life but were almost impossible to diagnose.

  • Property svn:eol-style set to native
File size: 11.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.bugreport;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Frame;
8import java.awt.GridBagConstraints;
9import java.awt.GridBagLayout;
10import java.awt.event.ActionEvent;
11
12import javax.swing.AbstractAction;
13import javax.swing.BorderFactory;
14import javax.swing.Icon;
15import javax.swing.JButton;
16import javax.swing.JCheckBox;
17import javax.swing.JDialog;
18import javax.swing.JLabel;
19import javax.swing.JOptionPane;
20import javax.swing.JPanel;
21import javax.swing.SwingUtilities;
22import javax.swing.UIManager;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.actions.ExpertToggleAction;
26import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference;
27import org.openstreetmap.josm.gui.util.GuiHelper;
28import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
29import org.openstreetmap.josm.gui.widgets.UrlLabel;
30import org.openstreetmap.josm.plugins.PluginDownloadTask;
31import org.openstreetmap.josm.plugins.PluginHandler;
32import org.openstreetmap.josm.tools.GBC;
33import org.openstreetmap.josm.tools.ImageProvider;
34import org.openstreetmap.josm.tools.InputMapUtils;
35import org.openstreetmap.josm.tools.OpenBrowser;
36import org.openstreetmap.josm.tools.bugreport.BugReport;
37import org.openstreetmap.josm.tools.bugreport.BugReportQueue.SuppressionMode;
38import org.openstreetmap.josm.tools.bugreport.BugReportSender;
39import org.openstreetmap.josm.tools.bugreport.BugReportSender.BugReportSendingHandler;
40import org.openstreetmap.josm.tools.bugreport.ReportedException;
41
42/**
43 * This is a dialog that can be used to display a bug report.
44 * <p>
45 * It displays the bug to the user and asks the user to submit a bug report.
46 * @author Michael Zangl
47 * @since 10649
48 */
49public class BugReportDialog extends JDialog {
50 private static final int MAX_MESSAGE_SIZE = 500;
51 // This is explicitly not an ExtendedDialog - we still want to be able to display bug reports if there are problems with preferences/..
52 private final JPanel content = new JPanel(new GridBagLayout());
53 private final BugReport report;
54 private final DebugTextDisplay textPanel;
55 private JCheckBox cbSuppressSingle;
56 private JCheckBox cbSuppressAll;
57
58 /**
59 * Default bug report callback that opens the bug report form in user browser
60 * and displays a dialog in case of error.
61 * @since 12790
62 */
63 public static final BugReportSendingHandler bugReportSendingHandler = new BugReportSendingHandler() {
64 @Override
65 public String sendingBugReport(String bugUrl, String statusText) {
66 return OpenBrowser.displayUrl(bugUrl);
67 }
68
69 @Override
70 public void failed(String errorMessage, String statusText) {
71 SwingUtilities.invokeLater(() -> {
72 JPanel errorPanel = new JPanel(new GridBagLayout());
73 errorPanel.add(new JMultilineLabel(
74 tr("Opening the bug report failed. Please report manually using this website:")),
75 GBC.eol().fill(GridBagConstraints.HORIZONTAL));
76 errorPanel.add(new UrlLabel(Main.getJOSMWebsite() + "/newticket", 2), GBC.eop().insets(8, 0, 0, 0));
77 errorPanel.add(new DebugTextDisplay(statusText));
78
79 JOptionPane.showMessageDialog(Main.parent, errorPanel, tr("You have encountered a bug in JOSM"),
80 JOptionPane.ERROR_MESSAGE);
81 });
82 }
83 };
84
85 /**
86 * Create a new dialog.
87 * @param report The report to display the dialog for.
88 */
89 public BugReportDialog(BugReport report) {
90 super(findParent(), tr("You have encountered a bug in JOSM"));
91 this.report = report;
92 textPanel = new DebugTextDisplay(report);
93 setContentPane(content);
94
95 addMessageSection();
96
97 addUpToDateSection();
98 // TODO: Notify user about plugin updates, then remove that notification that is displayed before this dialog is displayed.
99
100 addCreateTicketSection();
101
102 if (ExpertToggleAction.isExpert()) {
103 addDebugTextSection();
104 }
105
106 addIgnoreButton();
107
108 pack();
109 setModal(true);
110 setDefaultCloseOperation(DISPOSE_ON_CLOSE);
111
112 InputMapUtils.addEscapeAction(getRootPane(), new AbstractAction() {
113 @Override
114 public void actionPerformed(ActionEvent e) {
115 closeDialog();
116 }
117 });
118 }
119
120 /**
121 * The message informing the user what happened.
122 */
123 private void addMessageSection() {
124 String message = tr(
125 "An unexpected exception occurred.\n" + "This is always a coding error. If you are running the latest "
126 + "version of JOSM, please consider being kind and file a bug report.");
127 Icon icon = UIManager.getIcon("OptionPane.errorIcon");
128
129 JPanel panel = new JPanel(new GridBagLayout());
130
131 panel.add(new JLabel(icon), GBC.std().insets(0, 0, 10, 0));
132 JMultilineLabel messageLabel = new JMultilineLabel(message);
133 messageLabel.setMaxWidth(MAX_MESSAGE_SIZE);
134 panel.add(messageLabel, GBC.eol().fill());
135 content.add(panel, GBC.eop().fill(GBC.HORIZONTAL).insets(20, 10, 10, 10));
136 }
137
138 private void addDebugTextSection() {
139 JPanel panel = new JPanel(new GridBagLayout());
140 addBorder(panel, tr("Debug information"));
141 panel.add(textPanel, GBC.eop().fill());
142
143 panel.add(new JLabel(tr("Manually report at:")+' '), GBC.std());
144 panel.add(new UrlLabel(Main.getJOSMWebsite() + "/newticket"), GBC.std().fill(GBC.HORIZONTAL));
145 JButton copy = new JButton("Copy to clipboard");
146 copy.addActionListener(e -> textPanel.copyToClipboard());
147 panel.add(copy, GBC.eol().anchor(GBC.EAST));
148 content.add(panel, GBC.eop().fill());
149 }
150
151 private void addUpToDateSection() {
152 JPanel panel = new JosmUpdatePanel();
153 addBorder(panel, tr("Is JOSM up to date?"));
154 content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
155 }
156
157 private void addCreateTicketSection() {
158 JPanel panel = new JPanel(new GridBagLayout());
159 addBorder(panel, tr("Send bug report"));
160
161 JMultilineLabel helpText = new JMultilineLabel(
162 tr("If you are running the latest version of JOSM and the plugins, "
163 + "please file a bug report in our bugtracker.\n"
164 + "There the error information should already be "
165 + "filled in for you. Please include information on how to reproduce "
166 + "the error and try to supply as much detail as possible."));
167 helpText.setMaxWidth(MAX_MESSAGE_SIZE);
168 panel.add(helpText, GBC.eop().fill(GridBagConstraints.HORIZONTAL));
169
170 Component settings = GBC.glue(0, 0);
171 if (ExpertToggleAction.isExpert()) {
172 // The default settings should be fine in most situations.
173 settings = new BugReportSettingsPanel(report);
174 }
175 panel.add(settings);
176
177 JButton sendBugReportButton = new JButton(tr("Report Bug"), ImageProvider.getIfAvailable("bug"));
178 sendBugReportButton.addActionListener(e -> sendBug());
179 panel.add(sendBugReportButton, GBC.eol().insets(0, 0, 0, 0).anchor(GBC.SOUTHEAST));
180 content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
181 }
182
183 private static void addBorder(JPanel panel, String title) {
184 panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(title), BorderFactory
185 .createEmptyBorder(5, 5, 5, 5)));
186 }
187
188 private void addIgnoreButton() {
189 JPanel panel = new JPanel(new GridBagLayout());
190 cbSuppressSingle = new JCheckBox(tr("Suppress this error for this session."));
191 cbSuppressSingle.setVisible(false);
192 panel.add(cbSuppressSingle, GBC.std(0, 0).fill(GBC.HORIZONTAL));
193 cbSuppressAll = new JCheckBox(tr("Suppress further error dialogs for this session."));
194 cbSuppressAll.setVisible(false);
195 panel.add(cbSuppressAll, GBC.std(0, 1).fill(GBC.HORIZONTAL));
196 JButton ignore = new JButton(tr("Ignore this error."));
197 ignore.addActionListener(e -> closeDialog());
198 panel.add(ignore, GBC.std(1, 0).span(1, 2).anchor(GBC.CENTER));
199 content.add(panel, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 10, 10));
200 }
201
202 /**
203 * Shows or hides the suppress errors button
204 * @param showSuppress <code>true</code> to show the suppress errors checkbox.
205 */
206 public void setShowSuppress(boolean showSuppress) {
207 cbSuppressSingle.setVisible(showSuppress);
208 pack();
209 }
210
211 /**
212 * Shows or hides the suppress all errors button
213 * @param showSuppress <code>true</code> to show the suppress errors checkbox.
214 * @since 10819
215 */
216 public void setShowSuppressAll(boolean showSuppress) {
217 cbSuppressAll.setVisible(showSuppress);
218 pack();
219 }
220
221 /**
222 * Check if the checkbox to suppress further errors was selected
223 * @return <code>true</code> if the user wishes to suppress errors.
224 */
225 public SuppressionMode shouldSuppressFurtherErrors() {
226 if (cbSuppressAll.isSelected()) {
227 return SuppressionMode.ALL;
228 } else if (cbSuppressSingle.isSelected()) {
229 return SuppressionMode.SAME;
230 } else {
231 return SuppressionMode.NONE;
232 }
233 }
234
235 private void closeDialog() {
236 setVisible(false);
237 }
238
239 private void sendBug() {
240 BugReportSender.reportBug(textPanel.getCodeText());
241 }
242
243 /**
244 * A safe way to find a matching parent frame.
245 * @return The parent frame.
246 */
247 private static Frame findParent() {
248 return (Frame) (Main.parent instanceof Frame ? Main.parent : SwingUtilities.getAncestorOfClass(Frame.class, Main.parent));
249 }
250
251 /**
252 * Show the bug report for a given exception
253 * @param e The exception to display
254 * @param exceptionCounter A counter of how many exceptions have already been worked on
255 * @return The new suppression status
256 * @since 10819
257 */
258 public static SuppressionMode showFor(ReportedException e, int exceptionCounter) {
259 if (e.isOutOfMemory()) {
260 // do not translate the string, as translation may raise an exception
261 JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
262 "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
263 "where ### is the number of MB assigned to JOSM (e.g. 256).\n" +
264 "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.",
265 "Error",
266 JOptionPane.ERROR_MESSAGE
267 );
268 return SuppressionMode.NONE;
269 } else {
270 return GuiHelper.runInEDTAndWaitAndReturn(() -> {
271 PluginDownloadTask downloadTask = PluginHandler.updateOrdisablePluginAfterException(e);
272 if (downloadTask != null) {
273 // Ask for restart to install new plugin
274 PluginPreference.notifyDownloadResults(
275 Main.parent, downloadTask, !downloadTask.getDownloadedPlugins().isEmpty());
276 return SuppressionMode.NONE;
277 }
278
279 BugReport report = new BugReport(e);
280 BugReportDialog dialog = new BugReportDialog(report);
281 dialog.setShowSuppress(exceptionCounter > 0);
282 dialog.setShowSuppressAll(exceptionCounter > 1);
283 dialog.setVisible(true);
284 return dialog.shouldSuppressFurtherErrors();
285 });
286 }
287 }
288}
Note: See TracBrowser for help on using the repository browser.