/*
* Copyright (C) 2012 Jason Gedge <http://www.gedge.ca>
*
* This file is part of the OpGraph project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package ca.gedge.opgraph.app.components;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
/**
* A dialog that displays an exception to the user. The dialog initially shows
* a simple message explaining to the user that an error occurred, and the user
* has the option to expand and see the stack trace.
*
* TODO submit an error report (to github issues?)
* TODO option to not show errors of a specific type again
*/
public class ErrorDialog extends JDialog {
/**
* Displays a modal {@link ErrorDialog} for the given {@link Throwable}.
*
* @param thrown the {@link Throwable} to show
*
* @see ErrorDialog#ErrorDialog(Throwable)
*/
public static void showError(Throwable thrown) {
showError(thrown, null);
}
/**
* Displays a modal {@link ErrorDialog} with a given message.
*
* @param message the message to show
*
* @see ErrorDialog#ErrorDialog(String)
*/
public static void showError(String message) {
showError(null, message);
}
/**
* Displays a modal {@link ErrorDialog} for the given {@link Throwable}
* and with a given message.
*
* @param thrown the {@link Throwable} to show
* @param message the message to show
*
* @see ErrorDialog#ErrorDialog(Throwable, String)
*/
public static void showError(Throwable thrown, String message) {
final ErrorDialog dialog = new ErrorDialog(thrown);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.setLocationByPlatform(true);
dialog.setModal(true);
dialog.setVisible(true);
}
/** The {@link Throwable} this dialog is displaying */
private Throwable thrown;
/** The error message to display */
private String message;
/**
* Constructs an exception dialog from the given {@link Throwable} and
* with a default error message.
*
* @param thrown the {@link Throwable} to display in the dialog
*/
public ErrorDialog(Throwable thrown) {
this(thrown, null);
}
/**
* Constructs an exception dialog with the given message.
*
* @param message the message to show
*/
public ErrorDialog(String message) {
this(null, message);
}
/**
* Constructs an exception dialog from the given {@link Throwable}.
*
* @param thrown the {@link Throwable} to display in the dialog, or
* <code>null</code> to show without an exception
* @param message the error message to display, or a default message if
* <code>null</code>/empty. If <code>thrown</code> is not
* <code>null</code> then <code>thrown.getLocalizedMessage()</code>
* will be the default message if it is not <code>null</code>.
* Otherwise, a fixed message will be used.
*/
public ErrorDialog(Throwable thrown, String message) {
super(null, "Application Error", ModalityType.DOCUMENT_MODAL);
this.thrown = thrown;
this.message = (message == null ? "" : message.trim());
if(message.length() == 0)
this.message = "An error has occurred";
initializeComponents();
}
/**
* Initialize the components in this dialog.
*/
private void initializeComponents() {
setLayout(new BorderLayout(5, 5));
setSize(600, 400);
setResizable(false);
getRootPane().setBorder(new EmptyBorder(5, 5, 5, 5));
// Create error message label
final Icon errorIcon = UIManager.getIcon("OptionPane.errorIcon");
final JLabel errorLabel = new JLabel(message, errorIcon, SwingConstants.LEADING);
add(errorLabel, BorderLayout.NORTH);
// If we were given a Throwable, show its stack trace to the user
if(thrown != null) {
// Get the stack trace as a string
final StringWriter stringWriter = new StringWriter();
final PrintWriter stackTraceWriter = new PrintWriter(stringWriter);
thrown.printStackTrace(stackTraceWriter);
final String stackTraceString = stringWriter.toString();
// Stack trace label
final JLabel stackTraceLabel = new JLabel("<html><pre>" + stackTraceString + "</pre></html>");
final JScrollPane stackTraceScrollPane = new JScrollPane(stackTraceLabel);
stackTraceScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
stackTraceScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
add(stackTraceScrollPane, BorderLayout.CENTER);
}
// Create buttons
final JButton okButton = new JButton(new AbstractAction("Ok") {
@Override
public void actionPerformed(ActionEvent e) {
ErrorDialog.this.setVisible(false);
}
});
// Create a panel for buttons
final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.add(okButton);
add(buttonPanel, BorderLayout.SOUTH);
okButton.requestFocusInWindow();
}
}