001 /*
002 * Copyright (c) 1995-2010, The University of Sheffield. See the file
003 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004 *
005 * This file is part of GATE (see http://gate.ac.uk/), and is free
006 * software, licenced under the GNU Library General Public License,
007 * Version 2, June 1991 (in the distribution as file licence.html,
008 * and also available at http://gate.ac.uk/gate/licence.html).
009 *
010 * Thomas Heitz, 02/19/2009
011 *
012 * $Id$
013 */
014 package gate.swing;
015
016 import gate.Main;
017
018 import javax.swing.*;
019 import java.awt.event.ActionEvent;
020 import java.awt.*;
021 import java.io.StringWriter;
022 import java.io.PrintWriter;
023
024 public class ErrorDialog extends JOptionPane {
025
026 public ErrorDialog(Object[] message, int errorMessage, int defaultOption,
027 Icon icon, Object[] options, Object option) {
028 super(message, errorMessage, defaultOption, icon, options, option);
029 }
030
031 /**
032 * Display a user friendly error dialog with the possibility to show the
033 * stack trace and configuration and add actions as buttons.
034 *
035 * @param error exception that occurs, can be null; can contain newlines
036 * @param textMessage error message to display
037 * @param parentComponent determines the Frame in which the dialog is
038 * displayed; if null, or if the parentComponent has no Frame, a default
039 * Frame is used
040 * @param icon the icon to display in the dialog; null otherwise
041 * @param optionalActions optional actions that will be add as a button;
042 * null otherwise
043 */
044 public static void show(Throwable error, String textMessage,
045 Component parentComponent, Icon icon,
046 Action[] optionalActions) {
047
048 if (textMessage == null) { textMessage = ""; }
049 final JDialog dialog;
050 String detailedMessage = "";
051
052 // add the error stack trace in a scrollable text area, hidden at start
053 if (error != null) {
054 detailedMessage += "<h2>Message</h2>";
055 detailedMessage += error.getMessage();
056 detailedMessage += "<h2>Stack trace</h2>";
057 StringWriter sw = new StringWriter();
058 error.printStackTrace(new PrintWriter(sw));
059 detailedMessage += sw.toString()
060 .replaceAll("(at |Caused by:)", "<strong>$1</strong> ")
061 .replaceAll("(\\([A-Za-z]+\\.java:[0-9])+\\)", "<strong>$1</strong>");
062 }
063 detailedMessage += "<h2>System configuration</h2>";
064 detailedMessage += "<strong>GATE Version</strong> = " + Main.version + "\n";
065 detailedMessage += "<strong>GATE Build</strong> = " + Main.build + "\n";
066 for (Object property : System.getProperties().keySet()) {
067 String propertyValue = System.getProperty((String)property);
068 if (((String)property).contains("path")) {
069 // add space after path separator to enable wrapping
070 propertyValue = propertyValue.replaceAll(":", ": ");
071 }
072 detailedMessage += "<strong>" + property + "</strong> = " +
073 propertyValue + '\n';
074 }
075 detailedMessage = detailedMessage.replace("\n", "<br>\n");
076 detailedMessage = detailedMessage.replace("\t", " ");
077 JEditorPane messageArea = new JEditorPane("text/html", detailedMessage);
078 messageArea.setEditable(false);
079 messageArea.setMargin(new Insets(10, 10, 10 ,10));
080 final JScrollPane stackTracePane = new JScrollPane(messageArea);
081 stackTracePane.setVisible(false);
082
083 // put the message in an horizontal box
084 // with a toggle button to show/hide the stack trace
085 Box messageBox = Box.createHorizontalBox();
086 messageBox.add(new JLabel(textMessage.startsWith("<html>") ?
087 textMessage : "<html><body>" +
088 textMessage.replaceAll("\n", "<br>") + "</body></html>"));
089 messageBox.add(Box.createHorizontalStrut(5));
090 final JToggleButton toggleButton = new JToggleButton();
091 toggleButton.setToolTipText(
092 "Show the error stack trace and system configuration");
093 toggleButton.setMargin(new Insets(2, 4, 2, 2));
094 messageBox.add(toggleButton);
095 messageBox.add(Box.createHorizontalGlue());
096
097 // add new buttons from the optionalActions parameter
098 Object[] options =
099 new Object[(optionalActions == null) ? 1 : optionalActions.length + 1];
100 if (optionalActions != null) {
101 for (int i = 0; i < optionalActions.length; i++) {
102 options[i] = optionalActions[i].getValue(Action.NAME);
103 }
104 }
105 // add the cancel button
106 options[options.length-1] = "Let it be";
107 Object[] message = { messageBox, stackTracePane };
108
109 // create the dialog
110 ErrorDialog pane = new ErrorDialog(message, JOptionPane.ERROR_MESSAGE,
111 JOptionPane.DEFAULT_OPTION, icon, options, options[options.length-1]);
112 dialog = pane.createDialog(parentComponent,
113 "Gate has encountered a little problem...");
114 dialog.setResizable(true);
115
116 // add a listener for the Detail button
117 toggleButton.setAction(new AbstractAction("Detail") {
118 public void actionPerformed(ActionEvent e) {
119 SwingUtilities.invokeLater(new Runnable() {
120 public void run() {
121 stackTracePane.setVisible(toggleButton.isSelected());
122 if (toggleButton.isSelected()) {
123 Dimension screenSize =
124 Toolkit.getDefaultToolkit().getScreenSize();
125 dialog.setBounds(
126 (screenSize.width-700)/2, (screenSize.height-500)/2, 700, 500);
127 } else {
128 dialog.pack();
129 }
130 }
131 });
132 }
133 });
134
135 // show the dialog
136 dialog.pack();
137 dialog.setVisible(true);
138
139 // do the user selected action
140 Object choice = pane.getValue();
141 if (choice == null
142 || choice.equals("Let it be")
143 || optionalActions == null) {
144 dialog.dispose();
145 return;
146 }
147 for (int i = 0; i < optionalActions.length; i++) {
148 if (options[i].equals(choice)) {
149 optionalActions[i].actionPerformed(null);
150 pane.setValue(JOptionPane.UNINITIALIZED_VALUE);
151 break;
152 }
153 }
154 }
155
156 }
|