Ticket #13193: patch-fix-13193.2.patch

File patch-fix-13193.2.patch, 24.8 KB (added by michael2402, 8 years ago)
  • src/org/openstreetmap/josm/gui/ExtendedDialog.java

    diff --git a/src/org/openstreetmap/josm/gui/ExtendedDialog.java b/src/org/openstreetmap/josm/gui/ExtendedDialog.java
    index b7b6afb..28bb484 100644
    a b import static org.openstreetmap.josm.tools.I18n.tr;  
    55
    66import java.awt.Component;
    77import java.awt.Dimension;
     8import java.awt.Frame;
    89import java.awt.GridBagConstraints;
    910import java.awt.GridBagLayout;
    1011import java.awt.Insets;
    public class ExtendedDialog extends JDialog {  
    145146    }
    146147
    147148    public ExtendedDialog(Component parent, String title, String[] buttonTexts, boolean modal, boolean disposeOnClose) {
    148         super(GuiHelper.getFrameForComponent(parent), title, modal ? ModalityType.DOCUMENT_MODAL : ModalityType.MODELESS);
     149        super(searchRealParent(parent), title, modal ? ModalityType.DOCUMENT_MODAL : ModalityType.MODELESS);
    149150        this.parent = parent;
    150151        this.modal = modal;
    151152        bTexts = Utils.copyArray(buttonTexts);
    public class ExtendedDialog extends JDialog {  
    155156        this.disposeOnClose = disposeOnClose;
    156157    }
    157158
     159    private static Frame searchRealParent(Component parent) {
     160        if (parent == null) {
     161            return null;
     162        } else {
     163            return GuiHelper.getFrameForComponent(parent);
     164        }
     165    }
     166
    158167    /**
    159168     * Allows decorating the buttons with icons.
    160169     * @param buttonIcons The button icons
  • src/org/openstreetmap/josm/tools/GBC.java

    diff --git a/src/org/openstreetmap/josm/tools/GBC.java b/src/org/openstreetmap/josm/tools/GBC.java
    index 7dd8553..0261e61 100644
    a b public final class GBC extends GridBagConstraints {  
    9696    }
    9797
    9898    /**
     99     * Adds insets to this GBC.
     100     * @param insets The insets in all directions.
     101     * @return This constraint for chaining.
     102     * @since xxx
     103     */
     104    public GBC insets(int insets) {
     105        insets(insets, insets, insets, insets);
     106        return this;
     107    }
     108
     109    /**
    99110     * Specifies how to distribute extra horizontal space.
    100111     * @param weightx   Weight in horizontal direction
    101112     * @param weighty   Weight in vertical direction
  • src/org/openstreetmap/josm/tools/bugreport/BugReport.java

    diff --git a/src/org/openstreetmap/josm/tools/bugreport/BugReport.java b/src/org/openstreetmap/josm/tools/bugreport/BugReport.java
    index 9b4aea6..360c509 100644
    a b  
    22package org.openstreetmap.josm.tools.bugreport;
    33
    44import java.io.PrintWriter;
     5import java.io.Serializable;
    56import java.io.StringWriter;
    67import java.util.concurrent.CopyOnWriteArrayList;
    78
    import org.openstreetmap.josm.actions.ShowStatusReportAction;  
    3738 * @author Michael Zangl
    3839 * @since 10285
    3940 */
    40 public final class BugReport {
     41public final class BugReport implements Serializable {
     42    private static final long serialVersionUID = 1L;
     43
    4144    private boolean includeStatusReport = true;
    4245    private boolean includeData = true;
    4346    private boolean includeAllStackTraces;
  • new file src/org/openstreetmap/josm/tools/bugreport/BugReportDialog.java

    diff --git a/src/org/openstreetmap/josm/tools/bugreport/BugReportDialog.java b/src/org/openstreetmap/josm/tools/bugreport/BugReportDialog.java
    new file mode 100644
    index 0000000..62027ef
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.tools.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;
     10
     11import javax.swing.BorderFactory;
     12import javax.swing.Icon;
     13import javax.swing.JButton;
     14import javax.swing.JCheckBox;
     15import javax.swing.JDialog;
     16import javax.swing.JLabel;
     17import javax.swing.JPanel;
     18import javax.swing.UIManager;
     19
     20import org.openstreetmap.josm.Main;
     21import org.openstreetmap.josm.actions.ExpertToggleAction;
     22import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
     23import org.openstreetmap.josm.gui.widgets.UrlLabel;
     24import org.openstreetmap.josm.tools.GBC;
     25import org.openstreetmap.josm.tools.ImageProvider;
     26
     27/**
     28 * This is a fialog that can be used to display a bug report.
     29 * <p>
     30 * It displays the bug to the user and asks the user to submit a bug report.
     31 * @author Michael Zangl
     32 * @since xxx
     33 */
     34public class BugReportDialog extends JDialog {
     35    private static final int MAX_MESSAGE_SIZE = 500;
     36    // This is explicitly not an ExtendedDialog - we still want to be able to display bug reports if there are problems with preferences/..
     37    private final JPanel content = new JPanel(new GridBagLayout());
     38    private final BugReport report;
     39    private final DebugTextDisplay textPanel;
     40    private JCheckBox cbSuppress;
     41
     42    /**
     43     * Create a new dialog.
     44     * @param report The report to display the dialog for.
     45     */
     46    public BugReportDialog(BugReport report) {
     47        super(findParent(), tr("You have encountered a bug in JOSM"));
     48        this.report = report;
     49        textPanel = new DebugTextDisplay(report);
     50        setContentPane(content);
     51
     52        addMessageSection();
     53
     54        addUpToDateSection();
     55        // TODO: Notify user about plugin updates
     56
     57        addCreateTicketSection();
     58
     59        if (ExpertToggleAction.isExpert()) {
     60            addDebugTextSection();
     61        }
     62
     63        addIgnoreButton();
     64
     65        pack();
     66        setModal(true);
     67        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
     68    }
     69
     70    /**
     71     * The message informing the user what happened.
     72     */
     73    private void addMessageSection() {
     74        String message = tr(
     75                "An unexpected exception occurred.\n" + "This is always a coding error. If you are running the latest "
     76                        + "version of JOSM, please consider being kind and file a bug report.");
     77        Icon icon = UIManager.getIcon("OptionPane.errorIcon");
     78
     79        JPanel panel = new JPanel(new GridBagLayout());
     80
     81        panel.add(new JLabel(icon), GBC.std().insets(0, 0, 10, 0));
     82        JMultilineLabel messageLabel = new JMultilineLabel(message);
     83        messageLabel.setMaxWidth(MAX_MESSAGE_SIZE);
     84        panel.add(messageLabel, GBC.eol().fill());
     85        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL).insets(20));
     86    }
     87
     88    private void addDebugTextSection() {
     89        JPanel panel = new JPanel(new GridBagLayout());
     90        addBorder(panel, tr("Debug information"));
     91        panel.add(textPanel, GBC.eop().fill());
     92
     93        panel.add(new JLabel(tr("Manually report at:")), GBC.std());
     94        panel.add(new UrlLabel(Main.getJOSMWebsite() + "/newticket"), GBC.std().fill(GBC.HORIZONTAL));
     95        JButton copy = new JButton("Copy to clipboard");
     96        copy.addActionListener(e -> textPanel.copyToClippboard());
     97        panel.add(copy, GBC.eol().anchor(GBC.EAST));
     98        content.add(panel, GBC.eop().fill());
     99    }
     100
     101    private void addUpToDateSection() {
     102        JPanel panel = new JosmUpdatePanel();
     103        addBorder(panel, tr("Is JOSM up to date?"));
     104        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
     105    }
     106
     107    private void addCreateTicketSection() {
     108        JPanel panel = new JPanel(new GridBagLayout());
     109        addBorder(panel, tr("Send bug report"));
     110
     111        JMultilineLabel helpText = new JMultilineLabel(
     112                tr("If you are running the latest version of JOSM and the plugins, "
     113                        + "please file a bug report in our bugtracker.\n"
     114                        + "There the error information should already be "
     115                        + "filled in for you. Please include information on how to reproduce "
     116                        + "the error and try to supply as much detail as possible."));
     117        helpText.setMaxWidth(MAX_MESSAGE_SIZE);
     118        panel.add(helpText, GBC.eop().fill(GridBagConstraints.HORIZONTAL));
     119
     120        if (ExpertToggleAction.isExpert()) {
     121            // The default settings should be fine in most situations.
     122            panel.add(new BugReportSettingsPanel(report), GBC.eop().fill(GBC.HORIZONTAL));
     123        }
     124
     125        JButton sendBugReportButton = new JButton(tr("Report Bug"), ImageProvider.get("bug"));
     126        sendBugReportButton.addActionListener(e -> sendBug());
     127        panel.add(sendBugReportButton, GBC.eop().anchor(GBC.EAST));
     128        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
     129    }
     130
     131    private static void addBorder(JPanel panel, String title) {
     132        panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(title), BorderFactory
     133                .createEmptyBorder(10, 10, 10, 10)));
     134    }
     135
     136    private void addIgnoreButton() {
     137        JPanel panel = new JPanel(new GridBagLayout());
     138        cbSuppress = new JCheckBox(tr("Suppress further error dialogs for this session."));
     139        cbSuppress.setVisible(false);
     140        panel.add(cbSuppress, GBC.std().fill(GBC.HORIZONTAL));
     141        JButton ignore = new JButton(tr("Ignore this error."));
     142        ignore.addActionListener(e -> closeDialog());
     143        panel.add(ignore, GBC.eol());
     144        content.add(panel, GBC.eol().fill(GBC.HORIZONTAL).insets(20));
     145    }
     146
     147    /**
     148     * Shows or hides the suppress errors button
     149     * @param showSuppress <code>true</code> to show the suppress errors checkbox.
     150     */
     151    public void setShowSuppress(boolean showSuppress) {
     152        cbSuppress.setVisible(showSuppress);
     153        pack();
     154    }
     155
     156    /**
     157     * Check if the checkbox to suppress further errors was selected
     158     * @return <code>true</code> if the user wishes to suppress errors.
     159     */
     160    public boolean shouldSuppressFurtherErrors() {
     161        return cbSuppress.isSelected();
     162    }
     163
     164    private void closeDialog() {
     165        setVisible(false);
     166    }
     167
     168    private void sendBug() {
     169        BugReportSender.reportBug(textPanel.getCodeText());
     170    }
     171
     172    /**
     173     * A safe way to find a matching parent frame.
     174     * @return The parent frame.
     175     */
     176    private static Frame findParent() {
     177        Component current = Main.parent;
     178        try {
     179            // avoid cycles/invalid hirarchies
     180            for (int i = 0; i < 20 && current != null; i++) {
     181                if (current instanceof Frame) {
     182                    return (Frame) current;
     183                }
     184                current = current.getParent();
     185            }
     186        } catch (RuntimeException e) {
     187            BugReport.intercept(e).put("current", current).warn();
     188        }
     189        return null;
     190    }
     191}
  • src/org/openstreetmap/josm/tools/bugreport/BugReportExceptionHandler.java

    diff --git a/src/org/openstreetmap/josm/tools/bugreport/BugReportExceptionHandler.java b/src/org/openstreetmap/josm/tools/bugreport/BugReportExceptionHandler.java
    index 94fa83e..461b73f 100644
    a b  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.tools.bugreport;
    33
    4 import static org.openstreetmap.josm.tools.I18n.tr;
    5 
    6 import java.awt.Component;
    74import java.awt.GraphicsEnvironment;
    8 import java.awt.GridBagConstraints;
    9 import java.awt.GridBagLayout;
    10 import java.io.IOException;
    11 import java.io.PrintWriter;
    12 import java.io.StringWriter;
    13 
    14 import javax.swing.JButton;
    15 import javax.swing.JCheckBox;
    16 import javax.swing.JLabel;
     5
    176import javax.swing.JOptionPane;
    18 import javax.swing.JPanel;
    197import javax.swing.SwingUtilities;
    208
    219import org.openstreetmap.josm.Main;
    22 import org.openstreetmap.josm.actions.ReportBugAction;
    23 import org.openstreetmap.josm.actions.ShowStatusReportAction;
    24 import org.openstreetmap.josm.data.Version;
    25 import org.openstreetmap.josm.gui.ExtendedDialog;
    2610import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference;
    27 import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
    28 import org.openstreetmap.josm.gui.widgets.UrlLabel;
    2911import org.openstreetmap.josm.plugins.PluginDownloadTask;
    3012import org.openstreetmap.josm.plugins.PluginHandler;
    31 import org.openstreetmap.josm.tools.GBC;
    32 import org.openstreetmap.josm.tools.WikiReader;
    3313
    3414/**
    3515 * An exception handler that asks the user to send a bug report.
    public final class BugReportExceptionHandler implements Thread.UncaughtException  
    7858        }
    7959
    8060        static void askForBugReport(final Throwable e) {
    81             String[] buttonTexts = new String[] {tr("Do nothing"), tr("Report Bug")};
    82             String[] buttonIcons = new String[] {"cancel", "bug"};
    83             int defaultButtonIdx = 1;
    84             String message = tr("An unexpected exception occurred.<br>" +
    85                     "This is always a coding error. If you are running the latest<br>" +
    86                     "version of JOSM, please consider being kind and file a bug report."
    87                     );
    88             // Check user is running current tested version, the error may already be fixed
    89             int josmVersion = Version.getInstance().getVersion();
    90             if (josmVersion != Version.JOSM_UNKNOWN_VERSION) {
    91                 try {
    92                     int latestVersion = Integer.parseInt(new WikiReader().
    93                             read(Main.getJOSMWebsite()+"/wiki/TestedVersion?format=txt").trim());
    94                     if (latestVersion > josmVersion) {
    95                         buttonTexts = new String[] {tr("Do nothing"), tr("Update JOSM"), tr("Report Bug")};
    96                         buttonIcons = new String[] {"cancel", "download", "bug"};
    97                         defaultButtonIdx = 2;
    98                         message = tr("An unexpected exception occurred. This is always a coding error.<br><br>" +
    99                                 "However, you are running an old version of JOSM ({0}),<br>" +
    100                                 "instead of using the current tested version (<b>{1}</b>).<br><br>"+
    101                                 "<b>Please update JOSM</b> before considering to file a bug report.",
    102                                 String.valueOf(josmVersion), String.valueOf(latestVersion));
    103                     }
    104                 } catch (IOException | NumberFormatException ex) {
    105                     Main.warn(ex, "Unable to detect latest version of JOSM:");
    106                 }
    107             }
    108             // Build panel
    109             JPanel pnl = new JPanel(new GridBagLayout());
    110             pnl.add(new JLabel("<html>" + message + "</html>"), GBC.eol());
    111             JCheckBox cbSuppress = null;
    112             if (exceptionCounter > 1) {
    113                 cbSuppress = new JCheckBox(tr("Suppress further error dialogs for this session."));
    114                 pnl.add(cbSuppress, GBC.eol());
    115             }
    11661            if (GraphicsEnvironment.isHeadless()) {
    11762                return;
    11863            }
    119             // Show dialog
    120             ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Unexpected Exception"), buttonTexts);
    121             ed.setButtonIcons(buttonIcons);
    122             ed.setIcon(JOptionPane.ERROR_MESSAGE);
    123             ed.setCancelButton(1);
    124             ed.setDefaultButton(defaultButtonIdx);
    125             ed.setContent(pnl);
    126             ed.setFocusOnDefaultButton(true);
    127             ed.showDialog();
    128             if (cbSuppress != null && cbSuppress.isSelected()) {
    129                 suppressExceptionDialogs = true;
    130             }
    131             if (ed.getValue() <= 1) {
    132                 // "Do nothing"
    133                 return;
    134             } else if (ed.getValue() < buttonTexts.length) {
    135                 // "Update JOSM"
    136                 try {
    137                     Main.platform.openUrl(Main.getJOSMWebsite());
    138                 } catch (IOException ex) {
    139                     Main.warn(ex, "Unable to access JOSM website:");
    140                 }
    141             } else {
    142                 // "Report bug"
    143                 try {
    144                     JPanel p = buildPanel(e);
    145                     JOptionPane.showMessageDialog(Main.parent, p, tr("You have encountered a bug in JOSM"), JOptionPane.ERROR_MESSAGE);
    146                 } catch (RuntimeException ex) {
    147                     Main.error(ex);
    148                 }
    149             }
     64            BugReport report = new BugReport(BugReport.intercept(e));
     65            BugReportDialog dialog = new BugReportDialog(report);
     66            dialog.setShowSuppress(exceptionCounter > 1);
     67            dialog.setVisible(true);
     68            suppressExceptionDialogs = dialog.shouldSuppressFurtherErrors();
    15069        }
    15170
    15271        @Override
    public final class BugReportExceptionHandler implements Thread.UncaughtException  
    195114        }
    196115    }
    197116
    198     static JPanel buildPanel(final Throwable e) {
    199         DebugTextDisplay textarea;
    200         if (e instanceof ReportedException) {
    201             // Temporary!
    202             textarea = new DebugTextDisplay(new BugReport((ReportedException) e));
    203         } else {
    204             StringWriter stack = new StringWriter();
    205             e.printStackTrace(new PrintWriter(stack));
    206             textarea = new DebugTextDisplay(ShowStatusReportAction.getReportHeader() + stack.getBuffer().toString());
    207         }
    208 
    209         JPanel p = new JPanel(new GridBagLayout());
    210         p.add(new JMultilineLabel(
    211                 tr("You have encountered an error in JOSM. Before you file a bug report " +
    212                         "make sure you have updated to the latest version of JOSM here:")),
    213                         GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    214         p.add(new UrlLabel(Main.getJOSMWebsite(), 2), GBC.eop().insets(8, 0, 0, 0));
    215         p.add(new JMultilineLabel(
    216                 tr("You should also update your plugins. If neither of those help please " +
    217                         "file a bug report in our bugtracker using this link:")),
    218                         GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    219         p.add(new JButton(new ReportBugAction(textarea.getCodeText())), GBC.eop().insets(8, 0, 0, 0));
    220         p.add(new JMultilineLabel(
    221                 tr("There the error information provided below should already be " +
    222                         "filled in for you. Please include information on how to reproduce " +
    223                         "the error and try to supply as much detail as possible.")),
    224                         GBC.eop().fill(GridBagConstraints.HORIZONTAL));
    225         p.add(new JMultilineLabel(
    226                 tr("Alternatively, if that does not work you can manually fill in the information " +
    227                         "below at this URL:")), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    228         p.add(new UrlLabel(Main.getJOSMWebsite()+"/newticket", 2), GBC.eop().insets(8, 0, 0, 0));
    229 
    230         if (textarea.copyToClippboard()) {
    231             p.add(new JLabel(tr("(The text has already been copied to your clipboard.)")),
    232                     GBC.eop().fill(GridBagConstraints.HORIZONTAL));
    233         }
    234 
    235         p.add(textarea, GBC.eop().fill());
    236 
    237         for (Component c: p.getComponents()) {
    238             if (c instanceof JMultilineLabel) {
    239                 ((JMultilineLabel) c).setMaxWidth(400);
    240             }
    241         }
    242         return p;
    243     }
    244 
    245117    /**
    246118     * Determines if an exception is currently being handled
    247119     * @return {@code true} if an exception is currently being handled, {@code false} otherwise
  • src/org/openstreetmap/josm/tools/bugreport/BugReportSettingsPanel.java

    diff --git a/src/org/openstreetmap/josm/tools/bugreport/BugReportSettingsPanel.java b/src/org/openstreetmap/josm/tools/bugreport/BugReportSettingsPanel.java
    index de214f0..9d8c1a4 100644
    a b public class BugReportSettingsPanel extends JPanel {  
    2525        statusReport.addChangeListener(e -> report.setIncludeStatusReport(statusReport.isSelected()));
    2626        add(statusReport);
    2727
    28         JCheckBox data = new JCheckBox(tr("Include information about the data that was worked on."));
     28        JCheckBox data = new JCheckBox(tr("Include information about the data you were working on."));
    2929        data.setSelected(report.isIncludeData());
    3030        data.addChangeListener(e -> report.setIncludeData(data.isSelected()));
    3131        add(data);
  • new file src/org/openstreetmap/josm/tools/bugreport/JosmUpdatePanel.java

    diff --git a/src/org/openstreetmap/josm/tools/bugreport/JosmUpdatePanel.java b/src/org/openstreetmap/josm/tools/bugreport/JosmUpdatePanel.java
    new file mode 100644
    index 0000000..d54f771
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.tools.bugreport;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.GridBagLayout;
     7import java.io.IOException;
     8
     9import javax.swing.JButton;
     10import javax.swing.JPanel;
     11import javax.swing.SwingUtilities;
     12
     13import org.openstreetmap.josm.Main;
     14import org.openstreetmap.josm.data.Version;
     15import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
     16import org.openstreetmap.josm.gui.widgets.UrlLabel;
     17import org.openstreetmap.josm.tools.GBC;
     18import org.openstreetmap.josm.tools.ImageProvider;
     19import org.openstreetmap.josm.tools.WikiReader;
     20
     21/**
     22 * This is a panel that displays the current JOSM version and the ability to update JOSM.
     23 * @author Michael Zangl
     24 * @since xxx
     25 */
     26public class JosmUpdatePanel extends JPanel {
     27    private final JMultilineLabel testedVersionField;
     28    private final int josmVersion;
     29
     30    /**
     31     * Create a new {@link JosmUpdatePanel}
     32     */
     33    public JosmUpdatePanel() {
     34        super(new GridBagLayout());
     35        josmVersion = Version.getInstance().getVersion();
     36
     37        add(new JMultilineLabel(tr("Your current version of JOSM is {0}", josmVersion)), GBC.eop().fill(GBC.HORIZONTAL));
     38        testedVersionField = new JMultilineLabel(tr("JOSM is searching for updates..."));
     39        add(testedVersionField, GBC.eop().fill(GBC.HORIZONTAL));
     40
     41        checkCurrentVersion();
     42    }
     43
     44    private void checkCurrentVersion() {
     45        new Thread(this::readCurrentVersion, "JOSM version checker").start();
     46    }
     47
     48    private void readCurrentVersion() {
     49        int testedVersion = getTestedVersion();
     50
     51        if (testedVersion < 0) {
     52            SwingUtilities.invokeLater(this::displayError);
     53        } else if (josmVersion < testedVersion) {
     54            SwingUtilities.invokeLater(() -> displayOutOfDate(testedVersion));
     55        } else {
     56            SwingUtilities.invokeLater(this::displayUpToDate);
     57        }
     58    }
     59
     60    private static int getTestedVersion() {
     61        try {
     62            String testedString = new WikiReader().read(Main.getJOSMWebsite() + "/wiki/TestedVersion?format=txt");
     63            return Integer.parseInt(testedString.trim());
     64        } catch (NumberFormatException | IOException e) {
     65            Main.warn(e, "Unable to detect latest version of JOSM:");
     66            return -1;
     67        }
     68    }
     69
     70    /**
     71     * Display that there was an error while checking the current version.
     72     */
     73    private void displayError() {
     74        testedVersionField.setText(tr("An error occured while checking if your JOSM instance is up to date."));
     75        showUpdateButton();
     76    }
     77
     78    private void displayUpToDate() {
     79        testedVersionField.setText(tr("JOSM is up to date."));
     80    }
     81
     82    private void displayOutOfDate(int testedVersion) {
     83        testedVersionField
     84                .setText(tr("JOSM is out of date. The current version is {0}. Try updateing JOSM.", testedVersion));
     85        showUpdateButton();
     86    }
     87
     88    private void showUpdateButton() {
     89        add(new JMultilineLabel(tr("Before you file a bug report make sure you have updated to the latest version of JOSM here:")), GBC.eol());
     90        add(new UrlLabel(Main.getJOSMWebsite(), 2), GBC.eop().insets(8, 0, 0, 0));
     91        JButton updateButton = new JButton(tr("Update JOSM"), ImageProvider.get("download"));
     92        updateButton.addActionListener(e -> openJosmUpdateSite());
     93        add(updateButton, GBC.eol().anchor(GBC.EAST));
     94    }
     95
     96    private static void openJosmUpdateSite() {
     97        try {
     98            Main.platform.openUrl(Main.getJOSMWebsite());
     99        } catch (IOException ex) {
     100            Main.warn(ex, "Unable to access JOSM website:");
     101        }
     102    }
     103}
  • test/unit/org/openstreetmap/josm/tools/bugreport/BugReportExceptionHandlerTest.java

    diff --git a/test/unit/org/openstreetmap/josm/tools/bugreport/BugReportExceptionHandlerTest.java b/test/unit/org/openstreetmap/josm/tools/bugreport/BugReportExceptionHandlerTest.java
    index b2d2bd3..f479d0b 100644
    a b  
    22package org.openstreetmap.josm.tools.bugreport;
    33
    44import static org.junit.Assert.assertFalse;
    5 import static org.junit.Assert.assertNotNull;
    65
    76import org.junit.Before;
    87import org.junit.Test;
    public class BugReportExceptionHandlerTest {  
    2221    }
    2322
    2423    /**
    25      * Unit test for {@link BugReportExceptionHandler#buildPanel} method.
    26      */
    27     @Test
    28     public void testBuildPanel() {
    29         assertNotNull(BugReportExceptionHandler.buildPanel(new Exception("testBuildPanel")));
    30     }
    31 
    32     /**
    3324     * Unit test for {@link BugReportExceptionHandler.BugReporterThread#askForBugReport} method.
    3425     */
    3526    @Test