ErrorDialog.java
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""&nbsp;&nbsp;");
077     JEditorPane messageArea = new JEditorPane("text/html", detailedMessage);
078     messageArea.setEditable(false);
079     messageArea.setMargin(new Insets(101010 ,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(2422));
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: 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)/2700500);
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 }