/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.common.bug; import illarion.common.util.MessageSource; import org.jetbrains.annotations.Contract; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.swing.*; import java.awt.*; import java.awt.Dialog.ModalityType; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * This is the dialog implementation for Swing. It will display a dialog that * contains the error problem description and the error message and allows the * user to choose what to do. * * @author Martin Karing <nitram@illarion.org> */ public final class ReportDialogSwing implements ReportDialog { /** * Button listener helper class. This class is assigned to the buttons of * the dialog. * * @author Martin Karing <nitram@illarion.org> */ private final class ButtonListener implements ActionListener { /** * The dialog that is closed upon calling this listener. */ @Nonnull private final JDialog closingDialog; /** * The result value that is set in case the button is pressed. */ private final int resultValue; /** * Public constructor so the parent class is able to create a instance. * Also this sets the result value that is put in place in case the * button this listener is assigned to is clicked. * * @param dialog the dialog that is closed upon calling this listener * @param setResult the result value that is supposed to be set */ public ButtonListener(@Nonnull JDialog dialog, int setResult) { resultValue = setResult; closingDialog = dialog; } /** * The action performed when the button is pressed. */ @Override public void actionPerformed(ActionEvent e) { setResult(resultValue); closingDialog.setVisible(false); } } /** * The newline string that is used in the dialog. */ private static final String NL = "\n"; /** * The data about the crash. */ @Nullable private CrashData crashData; /** * The source of the messages displayed in the dialog. */ @Nullable private MessageSource messages; /** * The result received from the displayed dialog. */ private int result; /** * Get the result of the dialog. */ @Override @Contract(pure = true) public int getResult() { return result; } /** * Set the crash data that is displayed in this dialog. */ @Override public void setCrashData(@Nullable CrashData data) { crashData = data; } /** * Set the source of the messages displayed in this dialog. */ @Override public void setMessageSource(MessageSource source) { messages = source; } /** * Create and show the dialog. This method blocks until the dialog is * closed. */ @Override public void showDialog() { if ((messages == null) || (crashData == null)) { throw new IllegalStateException("The message source and the crash data needs to be set."); } JDialog dialog = new JDialog(); dialog.setModalityType(ModalityType.APPLICATION_MODAL); dialog.setTitle(messages.getMessage("illarion.common.bug.Title")); dialog.setAlwaysOnTop(true); JPanel mainPanel = new JPanel(new BorderLayout(5, 5)); dialog.getContentPane().add(mainPanel); JTextArea introText = new JTextArea(messages.getMessage(crashData.getDescription())); introText.setMargin(new Insets(10, 10, 10, 10)); introText.setEditable(false); introText.setCursor(null); introText.setOpaque(false); introText.setFocusable(false); mainPanel.add(introText, BorderLayout.NORTH); JTextArea detailsText = new JTextArea(messages.getMessage("illarion.common.bug.details.Intro") + NL + NL + messages.getMessage( "illarion.common.bug.details.Application") + ' ' + crashData.getApplicationIdentifier().getApplicationName() + NL + messages.getMessage("illarion.common.bug.details.Version") + ' ' + crashData.getApplicationIdentifier() .getApplicationVersion() + NL + messages.getMessage("illarion.common.bug.details.OS") + ' ' + CrashData.getOSName() + NL + messages.getMessage("illarion.common.bug.details.Thread") + ' ' + crashData.getThreadName() + NL + messages.getMessage("illarion.common.bug.details.Stack") + NL + crashData.getStackBacktrace()); detailsText.setEditable(false); detailsText.setCursor(null); detailsText.setOpaque(false); detailsText.setFocusable(false); JScrollPane detailsScroll = new JScrollPane(detailsText); mainPanel.add(detailsScroll, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(new GridLayout(1, 4, 5, 5)); mainPanel.add(buttonPanel, BorderLayout.SOUTH); JButton alwaysButton = new JButton(messages.getMessage("illarion.common.bug.buttons.always")); JButton onceButton = new JButton(messages.getMessage("illarion.common.bug.buttons.once")); JButton notButton = new JButton(messages.getMessage("illarion.common.bug.buttons.not")); JButton neverButton = new JButton(messages.getMessage("illarion.common.bug.buttons.never")); alwaysButton.addActionListener(new ButtonListener(dialog, SEND_ALWAYS)); onceButton.addActionListener(new ButtonListener(dialog, SEND_ONCE)); notButton.addActionListener(new ButtonListener(dialog, SEND_NOT)); neverButton.addActionListener(new ButtonListener(dialog, SEND_NEVER)); buttonPanel.add(alwaysButton); buttonPanel.add(onceButton); buttonPanel.add(notButton); buttonPanel.add(neverButton); dialog.setPreferredSize(new Dimension(550, 300)); dialog.validate(); dialog.pack(); dialog.setLocationRelativeTo(null); setResult(SEND_NOT); dialog.setVisible(true); dialog.dispose(); } /** * Set the result value. This is used instead of a synthetic accessor. * * @param newResult the new result value */ void setResult(int newResult) { result = newResult; } }