package net.sf.colossus.util; import java.awt.Dimension; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Toolkit; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import net.sf.colossus.common.Options; /** * Small helper methods to deal with Exceptions, how to get them into * String-format and display them to the user etc.<br><br> * Displaying of the message dialog is also provided here, so that * otherwise non-GUI classes have a simple way to show a dialog, * without need to worry about being headless etc. */ public class ErrorUtils { private static final Logger LOGGER = Logger.getLogger(ErrorUtils.class .getName()); private static List<String> errorDuringFunctionalTest = new ArrayList<String>(); /** * Query the stacktrace items from an exception, and put them * nicely into a single string. * @param e An exception that was caught somewhere * @return A string object containing all the stack trace lines. */ public static String makeStackTraceString(Throwable e) { StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw, true)); String stackTrace = sw.toString(); return stackTrace; } public static void clearErrorDuringFunctionalTest() { errorDuringFunctionalTest.clear(); } /** * * @param reason * @throws IllegalArgumentException */ public static void setErrorDuringFunctionalTest(String reason) throws IllegalArgumentException { if (reason == null) { throw new IllegalArgumentException( "reason to setErrorDuringFunctionalTest must not be null!"); } errorDuringFunctionalTest.add(reason); } public static String getErrorDuringFunctionalTest() { StringBuilder errorList = new StringBuilder(""); for (String errorMsg : errorDuringFunctionalTest) { errorList.append(errorMsg + "\n"); } return errorList.toString(); } public static boolean checkErrorDuringFunctionalTest() { return !(errorDuringFunctionalTest.isEmpty()); } /** During stress-testing, don't bother to show message, * instead exit immediately: */ private static void exitIfStresstest() { if (Options.isStresstest()) { String info = "Exiting due to an Exception: " + "A dialog box should have been shown now, " + "but we are in stresstest so we rather exit immediately " + "to get data for troubleshooting."; LOGGER.info(info); System.exit(1); } } /** * Show display an error/warning in an JOptionPage message dialog, * typically for the situation that an exception had occured. * Creates a special frame for the dialog, if given frame is null. * If called during stresstest, do System.exit(1) with explanatory * message to logfile. If headless, display is skipped. * * @param frame A frame to be used as parent for the dialog. * If null, an own frame is created for that purpose. * @param message Message to be displayed in the dialog window * @param title Title of the dialog window * @param error If true, type is error message, for false only warning */ public static void showExceptionDialog(JFrame frame, String message, String title, boolean error) { // as method name says... exitIfStresstest(); // Skip copying to clipboard and showing of the message dialog // if there is no Graphics device available: if (GraphicsEnvironment.isHeadless()) { return; } // Try to copy the whole message text to clipboard already String copiedInfo = ""; boolean copied = copyToClipboard(message); if (!copied) { LOGGER.info("NOTE: Attempt to copy message to Clipboard failed."); } else { copiedInfo = "\n[This error message should now also be " + "in your clipboard.]"; } String frameTitle = "EXCEPTION CAUGHT - see dialog box!"; showTheDialog(frame, frameTitle, title, message + copiedInfo, error); } /** * Show display an error/warning in an JOptionPage message dialog, * but this one here typically NOT for the situation that an exception * had occured. Does NOT copy anything to clipboard. * Creates a special frame for the dialog, if given frame is null. * If called during stresstest, do System.exit(1) with explanatory * message to logfile. If headless, display is skipped. * * @param frame A frame to be used as parent for the dialog. * If null, an own frame is created for that purpose. * @param title Title of the dialog window * @param message Message to be displayed in the dialog window */ public static void showErrorDialog(JFrame frame, String title, String message) { // as method name says... exitIfStresstest(); /* During functional testing, don't bother to show message, * instead log it and return immediately: */ if (Options.isFunctionalTest()) { String info = "Exiting due to an Error or Exception: " + "A dialog box should have been shown now, " + "but we are in a functional test so we rather exit " + "immediately instead of waiting for user input ."; LOGGER.severe(info); setErrorDuringFunctionalTest("showErrorDialog requested"); return; } // Skip copying to clipboard and showing of the message dialog // if there is no Graphics device available: if (GraphicsEnvironment.isHeadless()) { return; } String frameTitle = "AN ERROR OCCURRED - see dialog box!"; boolean error = true; showTheDialog(frame, frameTitle, title, message, error); } /** * Show the dialog box with given parameters; * if necessary (no parent frame given), create own dummy frame * to avoid that the message dialog is hidden behind other GUI * frames/dialogs, and is not even visible in the task bar. * * @param frame A parent frame to use, might be null * @param frameTitle The title to use for the frame to create * @param title The title for the message dialog * @param message The actual message to show in the dialog * @param error Type of message (true for error, false for warning) */ private static void showTheDialog(JFrame frame, String frameTitle, String title, String message, boolean error) { JFrame showFrame = frame; if (showFrame == null) { showFrame = makeDummyErrorFrame(frameTitle != null ? frameTitle : "PROBLEM OCCURED - see dialog box!"); } JOptionPane.showMessageDialog(showFrame, message, title, error ? JOptionPane.ERROR_MESSAGE : JOptionPane.WARNING_MESSAGE); // If we created the dummy frame, must get also rid of it. if (frame == null) { showFrame.dispose(); } } /** * Creates a JFrame object which can be used as parent for a dialog; the * frame is centered and contains a text telling that it is a dummy frame * just for that purpose that one does not miss the message dialog. * * @returns The JFrame object that can be used as parent for the dialog */ private static JFrame makeDummyErrorFrame(String frameTitle) { JFrame f = new JFrame(frameTitle); Box panel = new Box(BoxLayout.Y_AXIS); panel.add(new JLabel( "This is a dummy frame. It is only created in order to display")); panel.add(new JLabel( "a message dialog box, which without this frame might be hidden")); panel .add(new JLabel( "behind some other window(s) and is easily missed, because it does")); panel.add(new JLabel("not show up in the task bar...")); f.getContentPane().add(panel); f.pack(); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); f.setLocation(new Point(d.width / 2 - f.getSize().width / 2, d.height / 2 - f.getSize().height / 2)); f.setVisible(true); f.requestFocus(); return f; } public static boolean copyToClipboard(String message) { boolean ok = false; try { ClipBoardAccess cbAccess = new ClipBoardAccess(); cbAccess.setClipboardContents(message); ok = true; } catch (Exception e) { // Whatever happened here, it does not matter, at least // it's not important enough to spoil any higher level // processing... so, make sure we never through any // problem up. } return ok; } }