Extract and interface for ExceptionHelper in package net.sf.openrocket.startup. ...
authorkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Mon, 19 Dec 2011 22:01:05 +0000 (22:01 +0000)
committerkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Mon, 19 Dec 2011 22:01:05 +0000 (22:01 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@237 180e2498-e6e9-4542-8430-84ac67f01cd8

22 files changed:
src/net/sf/openrocket/document/OpenRocketDocument.java
src/net/sf/openrocket/gui/adaptors/ColumnTableModel.java
src/net/sf/openrocket/gui/dialogs/ScaleDialog.java
src/net/sf/openrocket/gui/main/ComponentAddButtons.java
src/net/sf/openrocket/gui/main/ComponentIcons.java
src/net/sf/openrocket/gui/main/ExceptionHandler.java [deleted file]
src/net/sf/openrocket/gui/main/SimulationRunDialog.java
src/net/sf/openrocket/gui/main/SwingExceptionHandler.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/componenttree/ComponentTreeTransferHandler.java
src/net/sf/openrocket/gui/rocketfigure/RocketComponentShapes.java
src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
src/net/sf/openrocket/gui/util/Icons.java
src/net/sf/openrocket/gui/util/OpenFileWorker.java
src/net/sf/openrocket/gui/util/SaveCSVWorker.java
src/net/sf/openrocket/gui/util/SaveFileWorker.java
src/net/sf/openrocket/gui/util/SwingPreferences.java
src/net/sf/openrocket/l10n/ExceptionSuppressingTranslator.java
src/net/sf/openrocket/rocketcomponent/Rocket.java
src/net/sf/openrocket/startup/Application.java
src/net/sf/openrocket/startup/ExceptionHandler.java [new file with mode: 0644]
src/net/sf/openrocket/startup/Startup2.java
src/net/sf/openrocket/util/SafetyMutex.java

index 3853f4ab86a761529ea28b6864dc04ffc03d6d99..9cd3d841a5cc0c8059d357ee26ce1224bbcecd46 100644 (file)
@@ -11,7 +11,6 @@ import javax.swing.Action;
 import net.sf.openrocket.document.events.DocumentChangeEvent;
 import net.sf.openrocket.document.events.DocumentChangeListener;
 import net.sf.openrocket.document.events.SimulationChangeEvent;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
@@ -500,7 +499,7 @@ public class OpenRocketDocument implements ComponentChangeListener {
                
                if (!undoErrorReported) {
                        undoErrorReported = true;
-                       ExceptionHandler.handleErrorCondition("Undo/Redo error: " + error);
+                       Application.getExceptionHandler().handleErrorCondition("Undo/Redo error: " + error);
                }
        }
        
index 2e010f6e2f52cadc4a25e5bea10e827b78bd13d2..e50a8ea5b87cd2100e03320513c49d3482e431b8 100644 (file)
@@ -4,7 +4,7 @@ import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableColumn;
 import javax.swing.table.TableColumnModel;
 
-import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.startup.Application;
 
 public abstract class ColumnTableModel extends AbstractTableModel {
        private final Column[] columns;
@@ -47,7 +47,7 @@ public abstract class ColumnTableModel extends AbstractTableModel {
        public Object getValueAt(int row, int col) {
                if ((row < 0) || (row >= getRowCount()) ||
                                (col < 0) || (col >= columns.length)) {
-                       ExceptionHandler.handleErrorCondition("Error:  Requested illegal column/row, col=" + col + " row=" + row);
+                       Application.getExceptionHandler().handleErrorCondition("Error:  Requested illegal column/row, col=" + col + " row=" + row);
                        return null;
                }
                return columns[col].getValueAt(row);
index fb8b32fdc38b8715789347f1f99ddbc98d0b60fe..34f3d646d9a615d057aa1ef63479d2c39514f7a2 100644 (file)
@@ -25,7 +25,6 @@ import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.UnitSelector;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
@@ -410,7 +409,7 @@ public class ScaleDialog extends JDialog {
        private void doScale() {
                double mul = multiplier.getValue();
                if (!(SCALE_MIN <= mul && mul <= SCALE_MAX)) {
-                       ExceptionHandler.handleErrorCondition("Illegal multiplier value, mul=" + mul);
+                       Application.getExceptionHandler().handleErrorCondition("Illegal multiplier value, mul=" + mul);
                        return;
                }
                
index 611bbffa867c5f3d3b764836358317fdd391176e..fa92a671f57fb7f015b493e954c7c4309e564eee 100644 (file)
@@ -407,13 +407,13 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
 
                        if (c == null) {
                                // Should not occur
-                               ExceptionHandler.handleErrorCondition("ERROR:  Could not place new component.");
+                               Application.getExceptionHandler().handleErrorCondition("ERROR:  Could not place new component.");
                                updateEnabled();
                                return;
                        }
                        
                        if (constructor == null) {
-                               ExceptionHandler.handleErrorCondition("ERROR:  Construction of type not supported yet.");
+                               Application.getExceptionHandler().handleErrorCondition("ERROR:  Construction of type not supported yet.");
                                return;
                        }
                        
@@ -525,7 +525,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                                // Insert at the end of the parent
                                return new Pair<RocketComponent, Integer>(parent, null);
                        default:
-                               ExceptionHandler.handleErrorCondition("ERROR:  Bad position type: " + pos);
+                               Application.getExceptionHandler().handleErrorCondition("ERROR:  Bad position type: " + pos);
                                return null;
                        }
                }
@@ -572,7 +572,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                                sel = 2;
                                break;
                        default:
-                               ExceptionHandler.handleErrorCondition("ERROR:  JOptionPane returned " + sel);
+                               Application.getExceptionHandler().handleErrorCondition("ERROR:  JOptionPane returned " + sel);
                                return 0;
                        }
                        
index cd71c2a625b72f34bfbfb6beb9a5cc6808fddeff..b0071caaac95cd545f5194c53587274009e4eb01 100644 (file)
@@ -124,7 +124,7 @@ public class ComponentIcons {
        private static ImageIcon loadSmall(String file, String desc) {
                URL url = ClassLoader.getSystemResource(file);
                if (url == null) {
-                       ExceptionHandler.handleErrorCondition("ERROR:  Couldn't find file: " + file);
+                       Application.getExceptionHandler().handleErrorCondition("ERROR:  Couldn't find file: " + file);
                        return null;
                }
                return new ImageIcon(url, desc);
@@ -141,7 +141,7 @@ public class ComponentIcons {
                                bi = ImageIO.read(url);
                                bi2 = ImageIO.read(url); //  How the fsck can one duplicate a BufferedImage???
                        } catch (IOException e) {
-                               ExceptionHandler.handleErrorCondition("ERROR:  Couldn't read file: " + file, e);
+                               Application.getExceptionHandler().handleErrorCondition("ERROR:  Couldn't read file: " + file, e);
                                return new ImageIcon[] { null, null };
                        }
                        
@@ -176,7 +176,7 @@ public class ComponentIcons {
                        
                        return icons;
                } else {
-                       ExceptionHandler.handleErrorCondition("ERROR:  Couldn't find file: " + file);
+                       Application.getExceptionHandler().handleErrorCondition("ERROR:  Couldn't find file: " + file);
                        return new ImageIcon[] { null, null };
                }
        }
diff --git a/src/net/sf/openrocket/gui/main/ExceptionHandler.java b/src/net/sf/openrocket/gui/main/ExceptionHandler.java
deleted file mode 100644 (file)
index 83301da..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-package net.sf.openrocket.gui.main;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
-
-import net.sf.openrocket.gui.dialogs.BugReportDialog;
-import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.logging.TraceException;
-import net.sf.openrocket.startup.Application;
-
-
-public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
-       
-       private static final LogHelper log = Application.getLogger();
-       
-       private static final int MEMORY_RESERVE = 512 * 1024;
-       
-       /**
-        * A memory reserve of 0.5 MB of memory, that can be freed when showing the dialog.
-        * <p>
-        * This field is package-private so that the JRE cannot optimize its use away.
-        */
-       static volatile byte[] memoryReserve = null;
-       
-       private static ExceptionHandler instance = null;
-       
-
-       private volatile boolean handling = false;
-       
-       
-
-
-       @Override
-       public void uncaughtException(final Thread thread, final Throwable throwable) {
-               
-               // Free memory reserve if out of memory
-               if (isOutOfMemoryError(throwable)) {
-                       memoryReserve = null;
-                       handling = false;
-                       log.error("Out of memory error detected", throwable);
-               }
-               
-               if (isNonFatalJREBug(throwable)) {
-                       log.warn("Ignoring non-fatal JRE bug", throwable);
-                       return;
-               }
-               
-               log.error("Handling uncaught exception on thread=" + thread, throwable);
-               throwable.printStackTrace();
-               
-               if (handling) {
-                       log.warn("Exception is currently being handled, ignoring");
-                       return;
-               }
-               
-               try {
-                       handling = true;
-                       
-                       // Show on the EDT
-                       if (SwingUtilities.isEventDispatchThread()) {
-                               log.info("Exception handler running on EDT, showing dialog");
-                               showDialog(thread, throwable);
-                       } else {
-                               log.info("Exception handler not on EDT, invoking dialog on EDT");
-                               SwingUtilities.invokeAndWait(new Runnable() {
-                                       @Override
-                                       public void run() {
-                                               showDialog(thread, throwable);
-                                       }
-                               });
-                       }
-                       
-               } catch (Throwable ex) {
-                       
-                       // Make sure the handler does not throw any exceptions
-                       try {
-                               log.error("Caught exception while handling exception", ex);
-                               System.err.println("Exception in exception handler, dumping exception:");
-                               ex.printStackTrace();
-                       } catch (Exception ignore) {
-                       }
-                       
-               } finally {
-                       // Mark handling as completed
-                       handling = false;
-               }
-               
-       }
-       
-       
-       /**
-        * Handle an error condition programmatically without throwing an exception.
-        * This can be used in cases where recovery of the error is desirable.
-        * <p>
-        * This method is guaranteed never to throw an exception, and can thus be safely
-        * used in finally blocks.
-        * 
-        * @param message       the error message.
-        */
-       public static void handleErrorCondition(String message) {
-               log.error(1, message, new TraceException());
-               handleErrorCondition(new InternalException(message));
-       }
-       
-       
-       /**
-        * Handle an error condition programmatically without throwing an exception.
-        * This can be used in cases where recovery of the error is desirable.
-        * <p>
-        * This method is guaranteed never to throw an exception, and can thus be safely
-        * used in finally blocks.
-        * 
-        * @param message       the error message.
-        * @param exception     the exception that occurred.
-        */
-       public static void handleErrorCondition(String message, Throwable exception) {
-               log.error(1, message, exception);
-               handleErrorCondition(new InternalException(message, exception));
-       }
-       
-       
-       /**
-        * Handle an error condition programmatically without throwing an exception.
-        * This can be used in cases where recovery of the error is desirable.
-        * <p>
-        * This method is guaranteed never to throw an exception, and can thus be safely
-        * used in finally blocks.
-        * 
-        * @param exception             the exception that occurred.
-        */
-       public static void handleErrorCondition(final Throwable exception) {
-               try {
-                       if (!(exception instanceof InternalException)) {
-                               log.error(1, "Error occurred", exception);
-                       }
-                       final Thread thread = Thread.currentThread();
-                       final ExceptionHandler handler = instance;
-                       
-                       if (handler == null) {
-                               log.error("Error condition occurred before exception handling has been initialized", exception);
-                               return;
-                       }
-                       
-                       if (SwingUtilities.isEventDispatchThread()) {
-                               log.info("Running in EDT, showing dialog");
-                               handler.showDialog(thread, exception);
-                       } else {
-                               log.info("Not in EDT, invoking dialog later");
-                               SwingUtilities.invokeLater(new Runnable() {
-                                       @Override
-                                       public void run() {
-                                               handler.showDialog(thread, exception);
-                                       }
-                               });
-                       }
-               } catch (Exception e) {
-                       log.error("Exception occurred in error handler", e);
-               }
-       }
-       
-       
-       /**
-        * The actual handling routine.
-        * 
-        * @param t             the thread that caused the exception, or <code>null</code>.
-        * @param e             the exception.
-        */
-       private void showDialog(Thread t, Throwable e) {
-               
-               // Out of memory
-               if (isOutOfMemoryError(e)) {
-                       log.info("Showing out-of-memory dialog");
-                       JOptionPane.showMessageDialog(null,
-                                       new Object[] {
-                                                       "OpenRocket is out of available memory!",
-                                                       "You should immediately close unnecessary design windows,",
-                                                       "save any unsaved designs and restart OpenRocket!"
-                                       }, "Out of memory", JOptionPane.ERROR_MESSAGE);
-                       return;
-               }
-               
-               // Create the message
-               String msg = e.getClass().getSimpleName() + ": " + e.getMessage();
-               if (msg.length() > 90) {
-                       msg = msg.substring(0, 80) + "...";
-               }
-               
-               // Unknown Error
-               if (!(e instanceof Exception) && !(e instanceof LinkageError)) {
-                       log.info("Showing Error dialog");
-                       JOptionPane.showMessageDialog(null,
-                                       new Object[] {
-                                                       "An unknown Java error occurred:",
-                                                       msg,
-                                                       "<html>You should immediately close unnecessary design windows,<br>" +
-                                                                       "save any unsaved designs and restart OpenRocket!"
-                                       }, "Unknown Java error", JOptionPane.ERROR_MESSAGE);
-                       return;
-               }
-               
-
-               // Normal exception, show question dialog               
-               log.info("Showing Exception dialog");
-               int selection = JOptionPane.showOptionDialog(null, new Object[] {
-                               "OpenRocket encountered an uncaught exception.  This typically signifies " +
-                                               "a bug in the software.",
-                               "<html><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + msg + "</em>",
-                               " ",
-                               "Please take a moment to report this bug to the developers.",
-                               "This can be done automatically if you have an Internet connection."
-                               }, "Uncaught exception", JOptionPane.DEFAULT_OPTION,
-                               JOptionPane.ERROR_MESSAGE, null,
-                               new Object[] { "View bug report", "Close" }, "View bug report");
-               
-               if (selection != 0) {
-                       // User cancelled
-                       log.user("User chose not to fill bug report");
-                       return;
-               }
-               
-               // Show bug report dialog
-               log.user("User requested sending bug report");
-               BugReportDialog.showExceptionDialog(null, t, e);
-       }
-       
-       
-
-       /**
-        * Registers the uncaught exception handler.  This should be used to ensure that
-        * all necessary registrations are performed.
-        */
-       public static void registerExceptionHandler() {
-               
-               if (instance == null) {
-                       instance = new ExceptionHandler();
-                       Thread.setDefaultUncaughtExceptionHandler(instance);
-                       
-                       // Handler for modal dialogs of Sun's Java implementation
-                       // See bug ID 4499199.
-                       System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName());
-                       
-                       reserveMemory();
-               }
-               
-       }
-       
-       
-       /**
-        * Reserve the buffer memory that is freed in case an OutOfMemoryError occurs.
-        */
-       private static void reserveMemory() {
-               memoryReserve = new byte[MEMORY_RESERVE];
-               for (int i = 0; i < MEMORY_RESERVE; i++) {
-                       memoryReserve[i] = (byte) i;
-               }
-       }
-       
-       
-
-       /**
-        * Return whether this throwable was caused by an OutOfMemoryError
-        * condition.  An exception is deemed to be caused by OutOfMemoryError
-        * if the throwable or any of its causes is of the type OutOfMemoryError.
-        * <p>
-        * This method is required because Apple's JRE implementation sometimes
-        * masks OutOfMemoryErrors within RuntimeExceptions.  Idiots.
-        * 
-        * @param t             the throwable to examine.
-        * @return              whether this is an out-of-memory condition.
-        */
-       private boolean isOutOfMemoryError(Throwable t) {
-               while (t != null) {
-                       if (t instanceof OutOfMemoryError)
-                               return true;
-                       t = t.getCause();
-               }
-               return false;
-       }
-       
-       
-
-       /**
-        * Handler used in modal dialogs by Sun Java implementation.
-        */
-       public static class AwtHandler {
-               public void handle(Throwable t) {
-                       if (instance != null) {
-                               instance.uncaughtException(Thread.currentThread(), t);
-                       }
-               }
-       }
-       
-       
-       /**
-        * Detect various non-fatal Sun JRE bugs.
-        * 
-        * @param t             the throwable
-        * @return              whether this exception should be ignored
-        */
-       private static boolean isNonFatalJREBug(Throwable t) {
-               
-               // NOTE:  Calling method logs the entire throwable, so log only message here
-               
-
-               /*
-                * Detect and ignore bug 6826104 in Sun JRE.
-                */
-               if (t instanceof NullPointerException) {
-                       StackTraceElement[] trace = t.getStackTrace();
-                       
-                       if (trace.length > 3 &&
-                                       trace[0].getClassName().equals("sun.awt.X11.XWindowPeer") &&
-                                       trace[0].getMethodName().equals("restoreTransientFor") &&
-
-                                       trace[1].getClassName().equals("sun.awt.X11.XWindowPeer") &&
-                                       trace[1].getMethodName().equals("removeFromTransientFors") &&
-
-                                       trace[2].getClassName().equals("sun.awt.X11.XWindowPeer") &&
-                                       trace[2].getMethodName().equals("setModalBlocked")) {
-                               log.warn("Ignoring Sun JRE bug (6826104): http://bugs.sun.com/view_bug.do?bug_id=6826104" + t);
-                               return true;
-                       }
-                       
-               }
-               
-
-               /*
-                * Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16.
-                */
-               if (t instanceof ArrayIndexOutOfBoundsException) {
-                       final String buggyClass = "sun.font.FontDesignMetrics";
-                       StackTraceElement[] elements = t.getStackTrace();
-                       if (elements.length >= 3 &&
-                                       (buggyClass.equals(elements[0].getClassName()) ||
-                                                       buggyClass.equals(elements[1].getClassName()) ||
-                                               buggyClass.equals(elements[2].getClassName()))) {
-                               log.warn("Ignoring Sun JRE bug 6828938:  " +
-                                               "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6828938): " + t);
-                               return true;
-                       }
-               }
-               
-               /*
-                * Detect and ignore bug 6561072 in Sun JRE 1.6.0_?
-                */
-               if (t instanceof NullPointerException) {
-                       StackTraceElement[] trace = t.getStackTrace();
-                       
-                       if (trace.length > 3 &&
-                                       trace[0].getClassName().equals("javax.swing.JComponent") &&
-                                       trace[0].getMethodName().equals("repaint") &&
-
-                                       trace[1].getClassName().equals("sun.swing.FilePane$2") &&
-                                       trace[1].getMethodName().equals("repaintListSelection") &&
-
-                                       trace[2].getClassName().equals("sun.swing.FilePane$2") &&
-                                       trace[2].getMethodName().equals("repaintSelection")) {
-                               log.warn("Ignoring Sun JRE bug 6561072 " +
-                                               "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6561072): " + t);
-                               return true;
-                       }
-               }
-               
-
-               /*
-                * Detect and ignore bug 6933331 in Sun JRE 1.6.0_18 and others
-                */
-               if (t instanceof IllegalStateException) {
-                       StackTraceElement[] trace = t.getStackTrace();
-                       
-                       if (trace.length > 1 &&
-                                       trace[0].getClassName().equals("sun.awt.windows.WComponentPeer") &&
-                                       trace[0].getMethodName().equals("getBackBuffer")) {
-                               log.warn("Ignoring Sun JRE bug 6933331 " +
-                                               "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6933331): " + t);
-                               return true;
-                       }
-               }
-               
-               /*
-                * Detect and ignore bug in Sun JRE 1.6.0_19
-                */
-               if (t instanceof NullPointerException) {
-                       StackTraceElement[] trace = t.getStackTrace();
-                       
-                       if (trace.length > 3 &&
-                                       trace[0].getClassName().equals("sun.awt.shell.Win32ShellFolder2") &&
-                                       trace[0].getMethodName().equals("pidlsEqual") &&
-
-                                       trace[1].getClassName().equals("sun.awt.shell.Win32ShellFolder2") &&
-                                       trace[1].getMethodName().equals("equals") &&
-
-                                       trace[2].getClassName().equals("sun.awt.shell.Win32ShellFolderManager2") &&
-                                       trace[2].getMethodName().equals("isFileSystemRoot")) {
-                               log.warn("Ignoring Sun JRE bug " +
-                                               "(see http://forums.sun.com/thread.jspa?threadID=5435324): " + t);
-                               return true;
-                       }
-               }
-               
-               /*
-                * Detect Sun JRE bug in D3D
-                */
-               if (t instanceof ClassCastException) {
-                       if (t.getMessage().equals("sun.awt.Win32GraphicsConfig cannot be cast to sun.java2d.d3d.D3DGraphicsConfig")) {
-                               log.warn("Ignoring Sun JRE bug " +
-                                               "(see http://forums.sun.com/thread.jspa?threadID=5440525): " + t);
-                               return true;
-                       }
-               }
-               
-               return false;
-       }
-       
-       
-       @SuppressWarnings("unused")
-       private static class InternalException extends Exception {
-               public InternalException() {
-                       super();
-               }
-               
-               public InternalException(String message, Throwable cause) {
-                       super(message, cause);
-               }
-               
-               public InternalException(String message) {
-                       super(message);
-               }
-               
-               public InternalException(Throwable cause) {
-                       super(cause);
-               }
-       }
-}
index 63248f531ce19dd78c5687130cdb1708c53f341c..c108030567921690797a37cf7f477ca796a417f0 100644 (file)
@@ -403,7 +403,7 @@ public class SimulationRunDialog extends JDialog {
                                
                        } else {
                                
-                               ExceptionHandler.handleErrorCondition("An exception occurred during the simulation", t);
+                               Application.getExceptionHandler().handleErrorCondition("An exception occurred during the simulation", t);
                                
                        }
                        simulationDone();
diff --git a/src/net/sf/openrocket/gui/main/SwingExceptionHandler.java b/src/net/sf/openrocket/gui/main/SwingExceptionHandler.java
new file mode 100644 (file)
index 0000000..b930e79
--- /dev/null
@@ -0,0 +1,424 @@
+package net.sf.openrocket.gui.main;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+import net.sf.openrocket.gui.dialogs.BugReportDialog;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.logging.TraceException;
+import net.sf.openrocket.startup.Application;
+
+
+public class SwingExceptionHandler implements Thread.UncaughtExceptionHandler, net.sf.openrocket.startup.ExceptionHandler {
+       
+       private static final LogHelper log = Application.getLogger();
+       
+       private static final int MEMORY_RESERVE = 512 * 1024;
+       
+       /**
+        * A memory reserve of 0.5 MB of memory, that can be freed when showing the dialog.
+        * <p>
+        * This field is package-private so that the JRE cannot optimize its use away.
+        */
+       volatile byte[] memoryReserve = null;
+       
+       private volatile boolean handling = false;
+       
+       
+
+
+       @Override
+       public void uncaughtException(final Thread thread, final Throwable throwable) {
+               
+               // Free memory reserve if out of memory
+               if (isOutOfMemoryError(throwable)) {
+                       memoryReserve = null;
+                       handling = false;
+                       log.error("Out of memory error detected", throwable);
+               }
+               
+               if (isNonFatalJREBug(throwable)) {
+                       log.warn("Ignoring non-fatal JRE bug", throwable);
+                       return;
+               }
+               
+               log.error("Handling uncaught exception on thread=" + thread, throwable);
+               throwable.printStackTrace();
+               
+               if (handling) {
+                       log.warn("Exception is currently being handled, ignoring");
+                       return;
+               }
+               
+               try {
+                       handling = true;
+                       
+                       // Show on the EDT
+                       if (SwingUtilities.isEventDispatchThread()) {
+                               log.info("Exception handler running on EDT, showing dialog");
+                               showDialog(thread, throwable);
+                       } else {
+                               log.info("Exception handler not on EDT, invoking dialog on EDT");
+                               SwingUtilities.invokeAndWait(new Runnable() {
+                                       @Override
+                                       public void run() {
+                                               showDialog(thread, throwable);
+                                       }
+                               });
+                       }
+                       
+               } catch (Throwable ex) {
+                       
+                       // Make sure the handler does not throw any exceptions
+                       try {
+                               log.error("Caught exception while handling exception", ex);
+                               System.err.println("Exception in exception handler, dumping exception:");
+                               ex.printStackTrace();
+                       } catch (Exception ignore) {
+                       }
+                       
+               } finally {
+                       // Mark handling as completed
+                       handling = false;
+               }
+               
+       }
+       
+       
+       /**
+        * Handle an error condition programmatically without throwing an exception.
+        * This can be used in cases where recovery of the error is desirable.
+        * <p>
+        * This method is guaranteed never to throw an exception, and can thus be safely
+        * used in finally blocks.
+        * 
+        * @param message       the error message.
+        */
+       @Override
+       public void handleErrorCondition(String message) {
+               log.error(1, message, new TraceException());
+               handleErrorCondition(new InternalException(message));
+       }
+       
+       
+       /**
+        * Handle an error condition programmatically without throwing an exception.
+        * This can be used in cases where recovery of the error is desirable.
+        * <p>
+        * This method is guaranteed never to throw an exception, and can thus be safely
+        * used in finally blocks.
+        * 
+        * @param message       the error message.
+        * @param exception     the exception that occurred.
+        */
+       @Override
+       public void handleErrorCondition(String message, Throwable exception) {
+               log.error(1, message, exception);
+               handleErrorCondition(new InternalException(message, exception));
+       }
+       
+       
+       /**
+        * Handle an error condition programmatically without throwing an exception.
+        * This can be used in cases where recovery of the error is desirable.
+        * <p>
+        * This method is guaranteed never to throw an exception, and can thus be safely
+        * used in finally blocks.
+        * 
+        * @param exception             the exception that occurred.
+        */
+       @Override
+       public void handleErrorCondition(final Throwable exception) {
+               try {
+                       if (!(exception instanceof InternalException)) {
+                               log.error(1, "Error occurred", exception);
+                       }
+                       final Thread thread = Thread.currentThread();
+                       
+                       if (SwingUtilities.isEventDispatchThread()) {
+                               log.info("Running in EDT, showing dialog");
+                               this.showDialog(thread, exception);
+                       } else {
+                               log.info("Not in EDT, invoking dialog later");
+                               final SwingExceptionHandler instance = this;
+                               SwingUtilities.invokeLater(new Runnable() {
+                                       @Override
+                                       public void run() {
+                                               instance.showDialog(thread, exception);
+                                       }
+                               });
+                       }
+               } catch (Exception e) {
+                       log.error("Exception occurred in error handler", e);
+               }
+       }
+       
+       
+       /**
+        * The actual handling routine.
+        * 
+        * @param t             the thread that caused the exception, or <code>null</code>.
+        * @param e             the exception.
+        */
+       private void showDialog(Thread t, Throwable e) {
+               
+               // Out of memory
+               if (isOutOfMemoryError(e)) {
+                       log.info("Showing out-of-memory dialog");
+                       JOptionPane.showMessageDialog(null,
+                                       new Object[] {
+                                                       "OpenRocket is out of available memory!",
+                                                       "You should immediately close unnecessary design windows,",
+                                                       "save any unsaved designs and restart OpenRocket!"
+                                       }, "Out of memory", JOptionPane.ERROR_MESSAGE);
+                       return;
+               }
+               
+               // Create the message
+               String msg = e.getClass().getSimpleName() + ": " + e.getMessage();
+               if (msg.length() > 90) {
+                       msg = msg.substring(0, 80) + "...";
+               }
+               
+               // Unknown Error
+               if (!(e instanceof Exception) && !(e instanceof LinkageError)) {
+                       log.info("Showing Error dialog");
+                       JOptionPane.showMessageDialog(null,
+                                       new Object[] {
+                                                       "An unknown Java error occurred:",
+                                                       msg,
+                                                       "<html>You should immediately close unnecessary design windows,<br>" +
+                                                                       "save any unsaved designs and restart OpenRocket!"
+                                       }, "Unknown Java error", JOptionPane.ERROR_MESSAGE);
+                       return;
+               }
+               
+
+               // Normal exception, show question dialog               
+               log.info("Showing Exception dialog");
+               int selection = JOptionPane.showOptionDialog(null, new Object[] {
+                               "OpenRocket encountered an uncaught exception.  This typically signifies " +
+                                               "a bug in the software.",
+                               "<html><em>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + msg + "</em>",
+                               " ",
+                               "Please take a moment to report this bug to the developers.",
+                               "This can be done automatically if you have an Internet connection."
+                               }, "Uncaught exception", JOptionPane.DEFAULT_OPTION,
+                               JOptionPane.ERROR_MESSAGE, null,
+                               new Object[] { "View bug report", "Close" }, "View bug report");
+               
+               if (selection != 0) {
+                       // User cancelled
+                       log.user("User chose not to fill bug report");
+                       return;
+               }
+               
+               // Show bug report dialog
+               log.user("User requested sending bug report");
+               BugReportDialog.showExceptionDialog(null, t, e);
+       }
+       
+       
+
+       /**
+        * Registers the uncaught exception handler.  This should be used to ensure that
+        * all necessary registrations are performed.
+        */
+       public void registerExceptionHandler() {
+               
+               Thread.setDefaultUncaughtExceptionHandler(this);
+
+               // Handler for modal dialogs of Sun's Java implementation
+               // See bug ID 4499199.
+               System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName());
+
+               reserveMemory();
+               
+       }
+       
+       
+       /**
+        * Reserve the buffer memory that is freed in case an OutOfMemoryError occurs.
+        */
+       private void reserveMemory() {
+               memoryReserve = new byte[MEMORY_RESERVE];
+               for (int i = 0; i < MEMORY_RESERVE; i++) {
+                       memoryReserve[i] = (byte) i;
+               }
+       }
+       
+       
+
+       /**
+        * Return whether this throwable was caused by an OutOfMemoryError
+        * condition.  An exception is deemed to be caused by OutOfMemoryError
+        * if the throwable or any of its causes is of the type OutOfMemoryError.
+        * <p>
+        * This method is required because Apple's JRE implementation sometimes
+        * masks OutOfMemoryErrors within RuntimeExceptions.  Idiots.
+        * 
+        * @param t             the throwable to examine.
+        * @return              whether this is an out-of-memory condition.
+        */
+       private boolean isOutOfMemoryError(Throwable t) {
+               while (t != null) {
+                       if (t instanceof OutOfMemoryError)
+                               return true;
+                       t = t.getCause();
+               }
+               return false;
+       }
+       
+       
+
+       /**
+        * Handler used in modal dialogs by Sun Java implementation.
+        */
+       public static class AwtHandler {
+               public void handle(Throwable t) {
+                               Application.getExceptionHandler().uncaughtException(Thread.currentThread(), t);
+               }
+       }
+       
+       
+       /**
+        * Detect various non-fatal Sun JRE bugs.
+        * 
+        * @param t             the throwable
+        * @return              whether this exception should be ignored
+        */
+       private boolean isNonFatalJREBug(Throwable t) {
+               
+               // NOTE:  Calling method logs the entire throwable, so log only message here
+               
+
+               /*
+                * Detect and ignore bug 6826104 in Sun JRE.
+                */
+               if (t instanceof NullPointerException) {
+                       StackTraceElement[] trace = t.getStackTrace();
+                       
+                       if (trace.length > 3 &&
+                                       trace[0].getClassName().equals("sun.awt.X11.XWindowPeer") &&
+                                       trace[0].getMethodName().equals("restoreTransientFor") &&
+
+                                       trace[1].getClassName().equals("sun.awt.X11.XWindowPeer") &&
+                                       trace[1].getMethodName().equals("removeFromTransientFors") &&
+
+                                       trace[2].getClassName().equals("sun.awt.X11.XWindowPeer") &&
+                                       trace[2].getMethodName().equals("setModalBlocked")) {
+                               log.warn("Ignoring Sun JRE bug (6826104): http://bugs.sun.com/view_bug.do?bug_id=6826104" + t);
+                               return true;
+                       }
+                       
+               }
+               
+
+               /*
+                * Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16.
+                */
+               if (t instanceof ArrayIndexOutOfBoundsException) {
+                       final String buggyClass = "sun.font.FontDesignMetrics";
+                       StackTraceElement[] elements = t.getStackTrace();
+                       if (elements.length >= 3 &&
+                                       (buggyClass.equals(elements[0].getClassName()) ||
+                                                       buggyClass.equals(elements[1].getClassName()) ||
+                                               buggyClass.equals(elements[2].getClassName()))) {
+                               log.warn("Ignoring Sun JRE bug 6828938:  " +
+                                               "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6828938): " + t);
+                               return true;
+                       }
+               }
+               
+               /*
+                * Detect and ignore bug 6561072 in Sun JRE 1.6.0_?
+                */
+               if (t instanceof NullPointerException) {
+                       StackTraceElement[] trace = t.getStackTrace();
+                       
+                       if (trace.length > 3 &&
+                                       trace[0].getClassName().equals("javax.swing.JComponent") &&
+                                       trace[0].getMethodName().equals("repaint") &&
+
+                                       trace[1].getClassName().equals("sun.swing.FilePane$2") &&
+                                       trace[1].getMethodName().equals("repaintListSelection") &&
+
+                                       trace[2].getClassName().equals("sun.swing.FilePane$2") &&
+                                       trace[2].getMethodName().equals("repaintSelection")) {
+                               log.warn("Ignoring Sun JRE bug 6561072 " +
+                                               "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6561072): " + t);
+                               return true;
+                       }
+               }
+               
+
+               /*
+                * Detect and ignore bug 6933331 in Sun JRE 1.6.0_18 and others
+                */
+               if (t instanceof IllegalStateException) {
+                       StackTraceElement[] trace = t.getStackTrace();
+                       
+                       if (trace.length > 1 &&
+                                       trace[0].getClassName().equals("sun.awt.windows.WComponentPeer") &&
+                                       trace[0].getMethodName().equals("getBackBuffer")) {
+                               log.warn("Ignoring Sun JRE bug 6933331 " +
+                                               "(see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6933331): " + t);
+                               return true;
+                       }
+               }
+               
+               /*
+                * Detect and ignore bug in Sun JRE 1.6.0_19
+                */
+               if (t instanceof NullPointerException) {
+                       StackTraceElement[] trace = t.getStackTrace();
+                       
+                       if (trace.length > 3 &&
+                                       trace[0].getClassName().equals("sun.awt.shell.Win32ShellFolder2") &&
+                                       trace[0].getMethodName().equals("pidlsEqual") &&
+
+                                       trace[1].getClassName().equals("sun.awt.shell.Win32ShellFolder2") &&
+                                       trace[1].getMethodName().equals("equals") &&
+
+                                       trace[2].getClassName().equals("sun.awt.shell.Win32ShellFolderManager2") &&
+                                       trace[2].getMethodName().equals("isFileSystemRoot")) {
+                               log.warn("Ignoring Sun JRE bug " +
+                                               "(see http://forums.sun.com/thread.jspa?threadID=5435324): " + t);
+                               return true;
+                       }
+               }
+               
+               /*
+                * Detect Sun JRE bug in D3D
+                */
+               if (t instanceof ClassCastException) {
+                       if (t.getMessage().equals("sun.awt.Win32GraphicsConfig cannot be cast to sun.java2d.d3d.D3DGraphicsConfig")) {
+                               log.warn("Ignoring Sun JRE bug " +
+                                               "(see http://forums.sun.com/thread.jspa?threadID=5440525): " + t);
+                               return true;
+                       }
+               }
+               
+               return false;
+       }
+       
+       
+       @SuppressWarnings("unused")
+       private static class InternalException extends Exception {
+               public InternalException() {
+                       super();
+               }
+               
+               public InternalException(String message, Throwable cause) {
+                       super(message, cause);
+               }
+               
+               public InternalException(String message) {
+                       super(message);
+               }
+               
+               public InternalException(Throwable cause) {
+                       super(cause);
+               }
+       }
+}
index b998b83f2a93244f25e3ea7256018228c41dbf56..4855112b77482f12cfe1652712dba3fb0acab3df 100644 (file)
@@ -14,7 +14,6 @@ import javax.swing.tree.TreeModel;
 import javax.swing.tree.TreePath;
 
 import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
@@ -177,7 +176,7 @@ public class ComponentTreeTransferHandler extends TransferHandler {
                        SwingUtilities.invokeLater(new Runnable() {
                                @Override
                                public void run() {
-                                       ExceptionHandler.handleErrorCondition(e);
+                                       Application.getExceptionHandler().handleErrorCondition(e);
                                }
                        });
                        return false;
index 3ed7741d183fcb9d20a5ff3f9b0d215a31b430eb..430962738c2e3fdd09859147989a883fcd11a4f5 100644 (file)
@@ -3,8 +3,8 @@ package net.sf.openrocket.gui.rocketfigure;
 
 import java.awt.Shape;
 
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.gui.scalefigure.RocketFigure;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Transformation;
 
 
@@ -18,7 +18,7 @@ public class RocketComponentShapes {
        public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
                        Transformation t) {
                // no-op
-               ExceptionHandler.handleErrorCondition("ERROR:  RocketComponent.getShapesSide called with "
+               Application.getExceptionHandler().handleErrorCondition("ERROR:  RocketComponent.getShapesSide called with "
                                + component);
                return new Shape[0];
        }
@@ -26,7 +26,7 @@ public class RocketComponentShapes {
        public static Shape[] getShapesBack(net.sf.openrocket.rocketcomponent.RocketComponent component,
                        Transformation t) {
                // no-op
-               ExceptionHandler.handleErrorCondition("ERROR:  RocketComponent.getShapesBack called with "
+               Application.getExceptionHandler().handleErrorCondition("ERROR:  RocketComponent.getShapesBack called with "
                                +component);
                return new Shape[0];
        }
index 8045f4541f8b9e5299cf4f7a09b92664537ff4fb..854eb17a1b4ad1555b0d01345ff1f782bb3ef3ef 100644 (file)
@@ -20,7 +20,6 @@ import java.util.Iterator;
 import java.util.LinkedHashSet;
 
 import net.sf.openrocket.gui.figureelements.FigureElement;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.gui.util.ColorConversion;
 import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.motor.Motor;
@@ -459,7 +458,7 @@ public class RocketFigure extends AbstractScaleFigure {
                }
                
                if (m == null) {
-                       ExceptionHandler.handleErrorCondition("ERROR: Rocket figure paint method not found for "
+                       Application.getExceptionHandler().handleErrorCondition("ERROR: Rocket figure paint method not found for "
                                        + component);
                        return new Shape[0];
                }
index 8adf191d529b52e6865a58e119630ae6647edb5a..5c76bf24f566c7cb9680271941de8e70e8986e23 100644 (file)
@@ -9,7 +9,6 @@ import javax.swing.Icon;
 import javax.swing.ImageIcon;
 
 import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
@@ -94,7 +93,7 @@ public class Icons {
                
                URL url = ClassLoader.getSystemResource(file);
                if (url == null) {
-                       ExceptionHandler.handleErrorCondition("Image file " + file + " not found, ignoring.");
+                       Application.getExceptionHandler().handleErrorCondition("Image file " + file + " not found, ignoring.");
                        return null;
                }
                return new ImageIcon(url, name);
index a52692e573ab4a8589f4e2fa3a373bfcb3dfc1ba..1b186408da148f636b48e2428a59d1f781de74e6 100644 (file)
@@ -12,7 +12,6 @@ import javax.swing.SwingWorker;
 
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.file.RocketLoader;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.MathUtil;
@@ -72,7 +71,7 @@ public class OpenFileWorker extends SwingWorker<OpenRocketDocument, Void> {
                        try {
                                is.close();
                        } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("Error closing file", e);
+                               Application.getExceptionHandler().handleErrorCondition("Error closing file", e);
                        }
                }
        }
index 585a63ac6fdf5f6f61967f6d1b5765bbffeda947..55ef4da7cd6b3706fe160816559c6ced080ec6ca 100644 (file)
@@ -13,9 +13,9 @@ import javax.swing.SwingWorker;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.file.CSVExport;
 import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ProgressOutputStream;
@@ -78,7 +78,7 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
                        try {
                                os.close();
                        } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("Error closing file", e);
+                               Application.getExceptionHandler().handleErrorCondition("Error closing file", e);
                        }
                }
                return null;
index b9191c4a77e240737f7a110de7c6ba1847407889..9e5f411743fdc676a5aaab814fd48d353032897e 100644 (file)
@@ -8,7 +8,7 @@ import javax.swing.SwingWorker;
 
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.file.RocketSaver;
-import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ProgressOutputStream;
 
 public class SaveFileWorker extends SwingWorker<Void, Void> {
@@ -48,7 +48,7 @@ public class SaveFileWorker extends SwingWorker<Void, Void> {
                        try {
                                os.close();
                        } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("Error closing file", e);
+                               Application.getExceptionHandler().handleErrorCondition("Error closing file", e);
                        }
                }
                return null;
index c1847a18599eb9a7281de91cae86c59a3083f69b..69e841e4efc3a5e5625a780397e9a5c024c808d8 100644 (file)
@@ -6,7 +6,6 @@ import java.awt.Point;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -16,17 +15,9 @@ import java.util.prefs.Preferences;
 
 import net.sf.openrocket.arch.SystemInfo;
 import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyComponent;
-import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.InternalComponent;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.MassObject;
-import net.sf.openrocket.rocketcomponent.RecoveryDevice;
 import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.RK4SimulationStepper;
 import net.sf.openrocket.simulation.SimulationOptions;
@@ -449,7 +440,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
                        }
                        
                } catch (BackingStoreException e) {
-                       ExceptionHandler.handleErrorCondition(e);
+                       Application.getExceptionHandler().handleErrorCondition(e);
                }
        }
        
index 4cca766b4af225d10b9218d1e989be8f4582fd94..dd916b6cde240c9464ea57bee78be6b291981695 100644 (file)
@@ -3,7 +3,7 @@ package net.sf.openrocket.l10n;
 import java.util.Locale;
 import java.util.MissingResourceException;
 
-import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.startup.Application;
 
 /**
  * A translator that suppresses MissingResourceExceptions and handles them gracefully.
@@ -46,7 +46,7 @@ public class ExceptionSuppressingTranslator implements Translator {
        private static synchronized void handleError(String key, MissingResourceException e) {
                if (!errorReported) {
                        errorReported = true;
-                       ExceptionHandler.handleErrorCondition("Can not find translation for '" + key + "' locale=" + Locale.getDefault(), e);
+                       Application.getExceptionHandler().handleErrorCondition("Can not find translation for '" + key + "' locale=" + Locale.getDefault(), e);
                }
        }
        
index 62d2c08040b36a1fdace813bbeb2156e1c121b27..226f9527c68ce585d722bcf380c0a5505fdefd22 100644 (file)
@@ -9,7 +9,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
@@ -459,7 +458,7 @@ public class Rocket extends RocketComponent {
                        freezeList = new LinkedList<ComponentChangeEvent>();
                        log.debug("Freezing Rocket");
                } else {
-                       ExceptionHandler.handleErrorCondition("Attempting to freeze Rocket when it is already frozen, " +
+                       Application.getExceptionHandler().handleErrorCondition("Attempting to freeze Rocket when it is already frozen, " +
                                        "freezeList=" + freezeList);
                }
        }
@@ -474,7 +473,7 @@ public class Rocket extends RocketComponent {
        public void thaw() {
                checkState();
                if (freezeList == null) {
-                       ExceptionHandler.handleErrorCondition("Attempting to thaw Rocket when it is not frozen");
+                       Application.getExceptionHandler().handleErrorCondition("Attempting to thaw Rocket when it is not frozen");
                        return;
                }
                if (freezeList.size() == 0) {
index 863776f7925be5e7e147688a7d53c1967563388c..da80895abe56c79df3e244402ea71eb6db1b4fe2 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.startup;
 
 import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
+import net.sf.openrocket.gui.main.SwingExceptionHandler;
 import net.sf.openrocket.l10n.ClassBasedTranslator;
 import net.sf.openrocket.l10n.DebugTranslator;
 import net.sf.openrocket.l10n.ExceptionSuppressingTranslator;
@@ -25,6 +26,8 @@ public final class Application {
        private static ThrustCurveMotorSetDatabase motorSetDatabase;
 
        private static Preferences preferences;
+       
+       private static SwingExceptionHandler exceptionHandler;
 
        // Initialize the logger to something sane for testing without executing Startup
        static {
@@ -130,6 +133,20 @@ public final class Application {
                Application.preferences = preferences;
        }
 
+       /**
+        * @return the exceptionHandler
+        */
+       public static SwingExceptionHandler getExceptionHandler() {
+               return exceptionHandler;
+       }
+
+       /**
+        * @param exceptionHandler the exceptionHandler to set
+        */
+       public static void setExceptionHandler(SwingExceptionHandler exceptionHandler) {
+               Application.exceptionHandler = exceptionHandler;
+       }
+
        /**
         * Return the database of all thrust curves loaded into the system.
         */
diff --git a/src/net/sf/openrocket/startup/ExceptionHandler.java b/src/net/sf/openrocket/startup/ExceptionHandler.java
new file mode 100644 (file)
index 0000000..fa11532
--- /dev/null
@@ -0,0 +1,12 @@
+package net.sf.openrocket.startup;\r
+\r
+public interface ExceptionHandler {\r
+\r
+       public void handleErrorCondition(String message);\r
+       public void handleErrorCondition(String message, Throwable exception);\r
+       public void handleErrorCondition(final Throwable exception);\r
+\r
+       \r
+       public void uncaughtException(final Thread thread, final Throwable throwable);\r
+       \r
+}\r
index 3c4f1dabfd72e3fec99a10d5f1fe7e4d0d1d1ce0..11ceb19049f523e7a7741d09c61c664309d205f1 100644 (file)
@@ -21,11 +21,11 @@ import net.sf.openrocket.file.iterator.FileIterator;
 import net.sf.openrocket.file.motor.MotorLoaderHelper;
 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
 import net.sf.openrocket.gui.main.BasicFrame;
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.gui.main.Splash;
+import net.sf.openrocket.gui.main.SwingExceptionHandler;
 import net.sf.openrocket.gui.util.GUIUtil;
-import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.gui.util.SimpleFileFilter;
+import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
@@ -92,7 +92,9 @@ public class Startup2 {
                
                // Setup the uncaught exception handler
                log.info("Registering exception handler");
-               ExceptionHandler.registerExceptionHandler();
+               SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
+               Application.setExceptionHandler(exceptionHandler);
+               exceptionHandler.registerExceptionHandler();
                
                // Start update info fetching
                final UpdateInfoRetriever updateInfo;
index 1e8267ebcca3577243cd77c0bc854d7bebb06c4f..646c54e4786e471fbb1d46acdeef4cb9e3edfbca 100644 (file)
@@ -2,7 +2,6 @@ package net.sf.openrocket.util;
 
 import java.util.LinkedList;
 
-import net.sf.openrocket.gui.main.ExceptionHandler;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.logging.TraceException;
 import net.sf.openrocket.startup.Application;
@@ -148,7 +147,7 @@ public abstract class SafetyMutex {
                        try {
                                
                                if (location == null) {
-                                       ExceptionHandler.handleErrorCondition("location is null");
+                                       Application.getExceptionHandler().handleErrorCondition("location is null");
                                        location = "";
                                }
                                checkState(false);
@@ -181,7 +180,7 @@ public abstract class SafetyMutex {
                                }
                                return true;
                        } catch (Exception e) {
-                               ExceptionHandler.handleErrorCondition("An exception occurred while unlocking a mutex, " +
+                               Application.getExceptionHandler().handleErrorCondition("An exception occurred while unlocking a mutex, " +
                                                "locking thread=" + lockingThread + " locations=" + locations, e);
                                return false;
                        }
@@ -225,7 +224,7 @@ public abstract class SafetyMutex {
                        
                        if (!errorReported) {
                                errorReported = true;
-                               ExceptionHandler.handleErrorCondition(ex);
+                               Application.getExceptionHandler().handleErrorCondition(ex);
                        } else {
                                log.error(message, ex);
                        }