package edu.mbl.jif.gui.error;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import javax.swing.*;
import javax.swing.text.*;
/**
* Usage:
* ErrorDialog.showError("This is an error message.", new Exception());
*
* from http://www.nakov.com/blog/2008/11/30/java-swing-error-dialog-with-exception-details/
* @author Svetlin Nakov
*/
@SuppressWarnings("serial")
public class ErrorDialog extends JDialog {
private static final String SHOW_DETAILS_TEXT = "Show Details ...";
private static final String HIDE_DETAILS_TEXT = "Hide Details";
private JButton jButtonClose;
private ImagePanel imagePanelErrorIcon;
private JButton jButtonShowHideDetails;
private JPanel jPanelBottom;
private JPanel jPanelCenter;
private JPanel jPanelTop;
private JScrollPane jScrollPaneErrorMsg;
private JTextPane jTextPaneErrorMsg;
private JScrollPane jScrollPaneException;
private JTextArea jTextAreaException;
private static final String ERROR_ICON_RESOURCE_LOCATION =
"edu/mbl/jif/gui/error/Error-Icon.gif";
public ErrorDialog(String errorMessage) {
this(errorMessage, null);
}
public ErrorDialog(String errorMessage, Throwable exception) {
this.setTitle("Error");
this.setModal(true);
this.setResizable(false);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
jPanelTop = new JPanel();
imagePanelErrorIcon = new ImagePanel(ERROR_ICON_RESOURCE_LOCATION);
jPanelTop.setLayout(null);
jPanelTop.setPreferredSize(new Dimension(480, 100));
imagePanelErrorIcon.setLocation(new Point(20, 36));
jPanelTop.add(imagePanelErrorIcon);
jTextPaneErrorMsg = new JTextPane();
jTextPaneErrorMsg.setFont(jTextPaneErrorMsg.getFont().deriveFont(
jTextPaneErrorMsg.getFont().getStyle() | Font.BOLD,
jTextPaneErrorMsg.getFont().getSize()+1));
jTextPaneErrorMsg.setBorder(null);
jTextPaneErrorMsg.setEditable(false);
jTextPaneErrorMsg.setBackground(null);
jScrollPaneErrorMsg = new JScrollPane(jTextPaneErrorMsg);
jScrollPaneErrorMsg.setBorder(null);
jScrollPaneErrorMsg.setSize(new Dimension(405, 80));
jScrollPaneErrorMsg.setLocation(new Point(71, 13));
jPanelTop.add(jScrollPaneErrorMsg);
jPanelCenter = new JPanel();
jPanelCenter.setSize(new Dimension(420, 300));
jTextAreaException = new JTextArea();
jScrollPaneException = new JScrollPane(jTextAreaException);
jScrollPaneException.setPreferredSize(new Dimension(470, 300));
jPanelCenter.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
jPanelCenter.add(jScrollPaneException);
jPanelBottom = new JPanel();
jButtonShowHideDetails = new JButton();
jButtonClose = new JButton();
jPanelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 15));
jButtonShowHideDetails.setText(SHOW_DETAILS_TEXT);
jButtonShowHideDetails.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
showHideExceptionDetails();
}
});
jPanelBottom.add(jButtonShowHideDetails);
jButtonClose.setText("Close");
jButtonClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
dispose();
}
});
jPanelBottom.add(jButtonClose);
this.setLayout(new BorderLayout());
this.add(jPanelTop, BorderLayout.NORTH);
this.add(jPanelCenter, BorderLayout.CENTER);
this.add(jPanelBottom, BorderLayout.SOUTH);
this.jTextPaneErrorMsg.setEditorKit(new VerticalCenteredEditorKit());
this.jTextPaneErrorMsg.setText(errorMessage);
this.jPanelCenter.setVisible(false);
if (exception != null) {
String exceptionText = getStackTraceAsString(exception);
jTextAreaException.setText(exceptionText);
jTextAreaException.setEditable(false);
} else {
this.jButtonShowHideDetails.setVisible(false);
}
// Make [Escape] key as close button
this.registerEscapeKey();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setModal(true);
this.pack();
centerDialogOnTheScreen();
}
private void centerDialogOnTheScreen() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dialogSize = this.getSize();
int centerPosX = (screenSize.width - dialogSize.width) / 2;
int centerPosY = (screenSize.height - dialogSize.height) / 2;
setLocation(centerPosX, centerPosY);
}
private void showHideExceptionDetails() {
if (this.jPanelCenter.isVisible()) {
// Hide the exception details
this.jButtonShowHideDetails.setText(SHOW_DETAILS_TEXT);
this.jPanelCenter.setVisible(false);
this.pack();
centerDialogOnTheScreen();
} else {
// Show the exception details
this.jButtonShowHideDetails.setText(HIDE_DETAILS_TEXT);
this.jPanelCenter.setVisible(true);
this.pack();
centerDialogOnTheScreen();
}
}
private String getStackTraceAsString(Throwable exception) {
Writer result = new StringWriter();
PrintWriter printWriter = new PrintWriter(result);
exception.printStackTrace(printWriter);
return result.toString();
}
/**
* Make the [Escape] key to behave like the [Close] button.
*/
public void registerEscapeKey() {
KeyStroke escapeKeyStroke =
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action escapeAction = new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
jButtonClose.doClick();
}
};
this.rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
escapeKeyStroke, "ESCAPE");
this.rootPane.getActionMap().put("ESCAPE", escapeAction);
}
public void hideAndDisposeDialog() {
this.setVisible(false);
this.dispose();
}
public static void showError(String errorMessage,
Throwable throwable) {
ErrorDialog errorDialog =
new ErrorDialog(errorMessage, throwable);
errorDialog.setVisible(true);
}
public static void showError(String errorMessage) {
ErrorDialog.showError(errorMessage, null);
}
public static void main(String[] args) {
ErrorDialog.showError("This is an error message.", new Exception());
}
}
@SuppressWarnings("serial")
class VerticalCenteredEditorKit extends StyledEditorKit {
public ViewFactory getViewFactory() {
return new StyledViewFactory();
}
static class StyledViewFactory implements ViewFactory {
public View create(Element elem) {
String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ContentElementName)) {
return new LabelView(elem);
} else if (kind.equals(AbstractDocument.ParagraphElementName)) {
return new ParagraphView(elem);
} else if (kind.equals(AbstractDocument.SectionElementName)) {
return new CenteredBoxView(elem, View.Y_AXIS);
} else if (kind.equals(StyleConstants.ComponentElementName)) {
return new ComponentView(elem);
} else if (kind.equals(StyleConstants.IconElementName)) {
return new IconView(elem);
}
}
// Default to text display
return new LabelView(elem);
}
}
static class CenteredBoxView extends BoxView {
public CenteredBoxView(Element elem, int axis) {
super(elem, axis);
}
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
int[] spans) {
super.layoutMajorAxis(targetSpan, axis, offsets, spans);
int textBlockHeight = 0;
int offset = 0;
for (int i = 0; i < spans.length; i++) {
textBlockHeight += spans[i];
}
offset = (targetSpan - textBlockHeight) / 2;
for (int i = 0; i < offsets.length; i++) {
offsets[i] += offset;
}
}
}
}