Updates for 0.9.5
authorplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sat, 28 Nov 2009 14:28:39 +0000 (14:28 +0000)
committerplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sat, 28 Nov 2009 14:28:39 +0000 (14:28 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@34 180e2498-e6e9-4542-8430-84ac67f01cd8

65 files changed:
ChangeLog
ReleaseNotes
TODO
build.properties
dists/OpenRocket-0.9.5-src.zip [new file with mode: 0644]
dists/OpenRocket-0.9.5.jar [new file with mode: 0644]
html/actions/updates.php
releasing.txt
src/net/sf/openrocket/aerodynamics/AerodynamicForces.java
src/net/sf/openrocket/aerodynamics/AtmosphericConditions.java
src/net/sf/openrocket/aerodynamics/FlightConditions.java
src/net/sf/openrocket/aerodynamics/WarningSet.java
src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java
src/net/sf/openrocket/communication/Communicator.java
src/net/sf/openrocket/communication/UpdateInfo.java
src/net/sf/openrocket/communication/UpdateInfoRetriever.java
src/net/sf/openrocket/database/Databases.java
src/net/sf/openrocket/document/OpenRocketDocument.java
src/net/sf/openrocket/document/Simulation.java
src/net/sf/openrocket/document/StorageOptions.java
src/net/sf/openrocket/file/RocketLoader.java
src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java
src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java
src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java
src/net/sf/openrocket/gui/adaptors/BooleanModel.java
src/net/sf/openrocket/gui/adaptors/DoubleModel.java
src/net/sf/openrocket/gui/adaptors/EnumModel.java
src/net/sf/openrocket/gui/adaptors/IntegerModel.java
src/net/sf/openrocket/gui/adaptors/MaterialModel.java
src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java
src/net/sf/openrocket/gui/components/URLLabel.java
src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
src/net/sf/openrocket/gui/configdialog/MotorConfig.java
src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
src/net/sf/openrocket/gui/dialogs/BugReportDialog.java
src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java
src/net/sf/openrocket/gui/dialogs/LicenseDialog.java
src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
src/net/sf/openrocket/gui/main/BasicFrame.java
src/net/sf/openrocket/gui/main/ComponentAddButtons.java
src/net/sf/openrocket/gui/main/SimulationRunDialog.java
src/net/sf/openrocket/gui/plot/Axis.java
src/net/sf/openrocket/gui/plot/PlotConfiguration.java
src/net/sf/openrocket/gui/plot/PlotDialog.java
src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java
src/net/sf/openrocket/motor/Motor.java
src/net/sf/openrocket/rocketcomponent/CenteringRing.java
src/net/sf/openrocket/rocketcomponent/Configuration.java
src/net/sf/openrocket/rocketcomponent/RocketComponent.java
src/net/sf/openrocket/rocketcomponent/ShockCord.java
src/net/sf/openrocket/simulation/SimulationConditions.java
src/net/sf/openrocket/simulation/SimulationStatus.java
src/net/sf/openrocket/util/BugException.java [new file with mode: 0644]
src/net/sf/openrocket/util/ConfigurationException.java [new file with mode: 0644]
src/net/sf/openrocket/util/FatalException.java [new file with mode: 0644]
src/net/sf/openrocket/util/LinearInterpolator.java
src/net/sf/openrocket/util/Pair.java
src/net/sf/openrocket/util/Prefs.java
src/net/sf/openrocket/util/Quaternion.java
src/net/sf/openrocket/util/Reflection.java
src/net/sf/openrocket/util/SaveCSVWorker.java
test/net/sf/openrocket/communication/HttpURLConnectionMock.java
test/net/sf/openrocket/util/ReflectionTest.java [new file with mode: 0644]

index 5967b47b0ed1e90f1731a882eb8d3d01f1325ec3..64c6e46a29452e4ceac30c7e051d96fdb0a6f132 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-11-28  Sampo Niskanen
+
+       * Released version 0.9.5
+       * [BUG] NPE when clearing combo box selections
+       * Minor fixes to update checking
+       * Added a few guidance texts
+
+2009-11-27  Sampo Niskanen
+
+       * [BUG] Fixed computing inner radius of centering ring
+       * Removed RuntimeException instantiation from all classes
+
 2009-11-24  Sampo Niskanen
 
        * Released version 0.9.4
index 698f5ca4f9f33bbf4ba244008f56b3bb204749db..c6786057ea6e4c01bb66fe8048e8f8c3cf3469ec 100644 (file)
@@ -1,4 +1,11 @@
 
+OpenRocket 0.9.5  (2009-11-28):
+-------------------------------
+
+Fixed a serious defect which prevented adding a tube coupler and
+centering ring on the same body tube.  Other minor improvements.
+
+
 OpenRocket 0.9.4  (2009-11-24):
 -------------------------------
 
diff --git a/TODO b/TODO
index ec071f934ae9819e79370926c39eb64b0a1ac4a1..79f2c962fcd0a73114e12a571973748e211e5d73 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,15 +1,12 @@
 
 Feature roadmap for OpenRocket 1.0
+----------------------------------
 
 
 Must-have:
 
-- Go through thrust curves and correct errors
-or
-- Hide duplicate motors
-
-
-Bugs:
+- Go through thrust curves and select best ones
+- Updated splash screen
 
 
 
@@ -20,28 +17,53 @@ Maybe:
 - Add slight randomness to yaw moment
 
 
+
 Postponed:
+----------
+
+
+Motor support:
 
 - Integration with thrustcurve.org (syncing?)
 - Reading thrust curves from external directory
 - Plot motor thrust curve
+- Water rocket modelling
 
-- Screw weights for nose cones / transitions
+
+Running:
 
 - Windows executable wrapper (launch4j)
 - Allow only one instance of OpenRocket running (RMI communication)
+- Running from command line
+
+
+UI issues:
+
 - Only schedule rocket figure update instead of each time updating it
-- Reading (writing) .RKT format
 - Importing flight data (file/altimeter)
-- Water rocket modelling
-- Landing scatter plots
-- Simulate other branches
+- Saving as SVG
 - Implement setDefaults() method for RocketComponent
 - BUG: Inner tube cluster rotation, edit with spinner arrows, slider wrong
 - NAR/CNES/etc competition validity checking
-- Running from command line
 - Print support
-- Saving as SVG
+
+
+Simulation:
+
+- Landing scatter plots
+- Simulate other branches
+
+
+Component support:
+
+- Screw weights for nose cones / transitions
+- Support for external pods
+- Support for tube fins
+
+
+Other:
+
+- Reading (writing) .RKT format
 
 
 Refactoring tasks:
@@ -57,7 +79,7 @@ Refactoring tasks:
 
 
 Done:
-
+-----
 - Search field in motor selection dialog
 - Motor selection/editing from Edit configurations dialog
 - Change FreeformFinSet to throw checked exceptions
@@ -88,4 +110,5 @@ In 0.9.4:
 - Simulation plot dialog forces dialog one button row too high (All/None)
 - Add styrofoam and depron materials
 - Inform user about software updates
-
+In 0.9.5:
+- Add label to motor panel to tell current number of stages
index 0fa9bd663d024b5def01891edaa1a1d687913dbc..cee4d6a197d73b9c442bb6d0c24c3fdf96bdb730 100644 (file)
@@ -1,7 +1,7 @@
 
 # The OpenRocket build version
 
-build.version=0.9.5pre
+build.version=0.9.5
 
 
 # The source of the package.  When building a package for a specific
diff --git a/dists/OpenRocket-0.9.5-src.zip b/dists/OpenRocket-0.9.5-src.zip
new file mode 100644 (file)
index 0000000..e58ce2d
Binary files /dev/null and b/dists/OpenRocket-0.9.5-src.zip differ
diff --git a/dists/OpenRocket-0.9.5.jar b/dists/OpenRocket-0.9.5.jar
new file mode 100644 (file)
index 0000000..648d908
Binary files /dev/null and b/dists/OpenRocket-0.9.5.jar differ
index 55e3e147293b30f3e3ef4fe536154f16e07cb9ad..aceea7931c52c5eb1de6148fc41d678fd498373d 100644 (file)
@@ -39,8 +39,11 @@ foreach (getallheaders() as $header => $value) {
 }
 
 // Log the request
-if (strlen($orversion) > 0 || strlen($orid) > 0 || strlen($oros) > 0
-       || strlen($orjava) > 0 || strlen($orcountry) > 0) {
+if ((strlen($orversion) > 0 || strlen($orid) > 0 || strlen($oros) > 0
+     || strlen($orjava) > 0 || strlen($orcountry) > 0) &&
+
+    (strlen($orversion) < 20 && strlen($orid) < 50 && strlen($oros) < 50
+     && strlen($orjava) < 50 && strlen($orcountry) < 50)) {
 
     $file = $logfiles . gmdate("Y-m");
     $line = gmdate("Y-m-d H:i:s") . ";" . $orid . ";" . $orversion .
@@ -55,11 +58,33 @@ if (strlen($orversion) > 0 || strlen($orid) > 0 || strlen($oros) > 0
 
 
 // Set HTTP content-type header
-header("Content-type: text/plain; charset=utf-8");
+// No charset allowed for 0.9.4
+//header("Content-type: text/plain; charset=utf-8");
+header("Content-type: text/plain");
 
+/*
+ * Currently all old versions are handled manually.
+ * Update checking was introduced in OpenRocket 0.9.4
+ */
 $version = $_GET["version"];
+$updates = "";
+
+if (preg_match("/^0\.9\.(4|5pre)/",$version)) {
+  $updates = "Version: 0.9.5\n" .
+    "5: Important bug fixes";
+}
+
+
+if (strlen($updates) == 0) {
 
-// No updates available
-header("HTTP/1.0 204 No Content");
+  // No updates available
+  header("HTTP/1.0 204 No Content");
+
+} else {
+
+  header("HTTP/1.0 200 OK");
+  echo $updates;
+
+}
 
 ?>
\ No newline at end of file
index 63164c4f8df71e4e131c5f4812cdc1378097d6cd..fb139efc97851f0840ef9b82555aa4bfa2517f22 100644 (file)
@@ -1,26 +1,31 @@
 
 Steps for making a release:
 
-1. Update build.properties for the new version.
-2. Update ReleaseNotes
-3. Update ChangeLog
-4. ant dist
-5. Test new features (not in project directory)
-6. Copy distribution files into dists/
-7. Update Eclipse project and commit files to SVN
-8. Tag the version in SVN, URL:
-   https://openrocket.svn.sourceforge.net/svnroot/openrocket/tags/Release_0.9.x
-9. Upload JAR and source distribution and ReleaseNotes to Sourceforge 
-    - Project Admin -> File Manager
-    - create new version directory under /openrocket
-    - upload JAR, ZIP and ReleaseNotes
-    - select ReleaseNotes properties, set as release notes
-    - select JAR properties, set release note file and default downloads
-    - select ZIP properties, set release note file
-10. Update HTML: index.html (release notes) download.html (version number)
-11. Update HTML to web server:
+1.  Update build.properties for the new version.
+2.  Update ReleaseNotes
+3.  Update ChangeLog
+4.  ant dist
+5.  Test new features (not in project directory)
+6.  Copy distribution files into dists/
+7.  Update Eclipse project and commit files to SVN
+8.  Tag the version in SVN, URL:
+    https://openrocket.svn.sourceforge.net/svnroot/openrocket/tags/Release_0.9.x
+9.  Update updates.php and test various versions using a different name:
+    scp updates.php plaa,openrocket@web.sourceforge.net:htdocs/actions/testupdates.php
+    java -Dopenrocket.debug.updateurl=http://openrocket.sourceforge.net/actions/testupdates.php -jar OpenRocket-0.9.4.jar
+10. Upload JAR and source distribution and ReleaseNotes to Sourceforge 
+     - Project Admin -> File Manager
+     - create new version directory under /openrocket
+     - upload JAR, ZIP and ReleaseNotes
+     - select ReleaseNotes properties, set as release notes
+     - select JAR properties, set release note file and default downloads
+     - select ZIP properties, set release note file
+11. Update HTML: index.html (release notes) download.html (version number)
+12. Update HTML to web server:
     scp * plaa,openrocket@web.sourceforge.net:htdocs/
-12. Test downloading from Sourceforge and web site
-13. Update build.properties to "pre" version + commit
-14. Send email about new release to openrocket-announce@lists.sourceforge.net
+13. Test downloading from Sourceforge and web site
+14. Update update.php to web server:
+    scp updates.php plaa,openrocket@web.sourceforge.net:htdocs/actions/
+15. Update build.properties to "pre" version + commit
+16. Send email about new release to openrocket-announce@lists.sourceforge.net
 
index 5a6abcb0df858680ce548908e0865fd23d3c004c..fbc9b7c079e7b5fa03160636c20127a446c59e8c 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.aerodynamics;
 
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 
 public class AerodynamicForces implements Cloneable {
@@ -132,7 +133,7 @@ public class AerodynamicForces implements Cloneable {
                try {
                        return (AerodynamicForces)super.clone();
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("CloneNotSupportedException?!?");
+                       throw new BugException("CloneNotSupportedException?!?");
                }
        }
        
index c36c525f2920ef206e8203ff5739f81ceadf7c4f..d2e910ea783e5d98c4f8e93e1364bf69a5a2b255 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.aerodynamics;
 
+import net.sf.openrocket.util.BugException;
+
 public class AtmosphericConditions implements Cloneable {
 
        /** Specific gas constant of dry air. */
@@ -92,7 +94,7 @@ public class AtmosphericConditions implements Cloneable {
                try {
                        return (AtmosphericConditions) super.clone();
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("BUG:  CloneNotSupportedException encountered!");
+                       throw new BugException("BUG:  CloneNotSupportedException encountered!");
                }
        }
        
index 58d964e1987583b1465af1c11f71f43a999bfb95..56712a2a0c7700585c36e043e8364b1be9ab0dfe 100644 (file)
@@ -7,6 +7,7 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
 import net.sf.openrocket.rocketcomponent.Configuration;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 import net.sf.openrocket.util.MathUtil;
 
@@ -369,7 +370,7 @@ public class FlightConditions implements Cloneable, ChangeSource {
                        cond.atmosphericConditions = atmosphericConditions.clone();
                        return cond;
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("BUG: clone not supported!",e);
+                       throw new BugException("BUG: clone not supported!",e);
                }
        }
 
index 32355bc32237c4546fb32460bec34ed641b68b8c..ead0625c0ccdb3ee93141d1978dd6c5000cf1210 100644 (file)
@@ -4,6 +4,8 @@ import java.util.AbstractSet;
 import java.util.ArrayList;
 import java.util.Iterator;
 
+import net.sf.openrocket.util.BugException;
+
 /**
  * A set that contains multiple <code>Warning</code>s.  When adding a
  * {@link Warning} to this set, the contents is checked for a warning of the
@@ -72,7 +74,7 @@ public class WarningSet extends AbstractSet<Warning> implements Cloneable {
                        return newSet;
                        
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("CloneNotSupportedException occurred, report bug!",e);
+                       throw new BugException("CloneNotSupportedException occurred, report bug!",e);
                }
        }
        
index 3f0e4e79387a0836d08d048e317d4835c2534081..c112a18aa9d27760fc9acfef0048d0d4222ade11 100644 (file)
@@ -10,6 +10,7 @@ import net.sf.openrocket.rocketcomponent.BodyTube;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.SymmetricComponent;
 import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.LinearInterpolator;
 import net.sf.openrocket.util.MathUtil;
@@ -172,7 +173,7 @@ public class SymmetricComponentCalc extends RocketComponentCalc {
                        return 0;
                
                if (!(component instanceof Transition)) {
-                       throw new RuntimeException("Pressure calculation of unknown type: "+
+                       throw new BugException("Pressure calculation of unknown type: "+
                                        component.getComponentName());
                }
                
index 24ed1f56fb0d996538b7ff94fbe1ce91eac265d4..06c666b7f59dada3bfeb54a0d1d1aac3b29a4c6a 100644 (file)
@@ -4,6 +4,8 @@ import java.io.UnsupportedEncodingException;
 import java.net.HttpURLConnection;
 import java.net.URLEncoder;
 
+import net.sf.openrocket.util.BugException;
+
 public abstract class Communicator {
 
        protected static final String BUG_REPORT_URL;
@@ -65,7 +67,7 @@ public abstract class Communicator {
                try {
                        return URLEncoder.encode(str, "UTF-8");
                } catch (UnsupportedEncodingException e) {
-                       throw new RuntimeException("Unsupported encoding UTF-8", e);
+                       throw new BugException("Unsupported encoding UTF-8", e);
                }
        }
        
index 73e39633b77efac81c86c5bcf089e54d58172b93..a9b0d0445e237097d0e27abe99c76bc71731fb08 100644 (file)
@@ -47,4 +47,9 @@ public class UpdateInfo {
                return (List<ComparablePair<Integer, String>>) updates.clone();
        }
        
+       @Override
+       public String toString() {
+               return "UpdateInfo[version=" + latestVersion + "; updates=" + updates.toString() + "]";
+       }
+       
 }
index 082f2b9f7491e85a62882a6a8209aeb1313b377e..4fd0782461b417289f21520d3bd2c2662cc6f88d 100644 (file)
@@ -153,7 +153,7 @@ public class UpdateInfoRetriever {
                                                        System.getProperty("java.version")));
                        connection.setRequestProperty("X-OpenRocket-Country", 
                                        Communicator.encode(System.getProperty("user.country") + " " +
-                                                       Communicator.encode(System.getProperty("user.timezone"))));
+                                                       System.getProperty("user.timezone")));
                        
                        InputStream is = null;
                        try {
@@ -169,15 +169,19 @@ public class UpdateInfoRetriever {
                                
                                if (connection.getResponseCode() != Communicator.UPDATE_INFO_UPDATE_AVAILABLE) {
                                        // Error communicating with server
+                                       System.out.println("Unknown response code: " + connection.getResponseCode());
                                        return;
                                }
                                
-                               if (!Communicator.UPDATE_INFO_CONTENT_TYPE.equalsIgnoreCase(
-                                               connection.getContentType())) {
+                               String contentType = connection.getContentType();
+                               if (contentType == null || 
+                                               contentType.toLowerCase().indexOf(Communicator.UPDATE_INFO_CONTENT_TYPE) < 0) {
                                        // Unknown response type
+                                       System.out.println("Unknown Content-type received:"+contentType);
                                        return;
                                }
                                
+                               System.out.println("Update is available");
                                
                                // Update is available, parse input
                                is = connection.getInputStream();
@@ -209,12 +213,13 @@ public class UpdateInfoRetriever {
                                if (version == null || version.length() == 0 || 
                                                version.equalsIgnoreCase(Prefs.getVersion())) {
                                        // Invalid response
+                                       System.out.println("Invalid version received, ignoring.");
                                        return;
                                }
                                
                                
                                info = new UpdateInfo(version, updates);
-                               
+                               System.out.println("Found update: " + info);
                        } finally {
                                try {
                                        if (is != null)
index cdf39c2e41ab6897e62accbb2728f28d449f1d8a..efb8cd6cb36a26f48ac1fed28403edba3179228c 100644 (file)
@@ -9,6 +9,7 @@ import net.sf.openrocket.file.GeneralMotorLoader;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.material.MaterialStorage;
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.util.ConfigurationException;
 import net.sf.openrocket.util.JarUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Prefs;
@@ -65,7 +66,8 @@ public class Databases {
                                MOTOR.loadDirectory(dir, ".*\\.[eE][nN][gG]$");
                        } catch (IOException e1) {
                                System.out.println("Could not read thrust curves from directory either.");
-                               throw new RuntimeException(e1);
+                               throw new ConfigurationException("Couldn't read thrust curves from either " +
+                                               "JAR file or system resource directory", e1);
                        }
                }
        }
index 164f76da6282d9d1f630c6710f47f5de4cf94a98..83c4b0b7ebeba0c15f5860bafde4c75a161e07a8 100644 (file)
@@ -17,6 +17,7 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Icons;
 
 
@@ -449,7 +450,7 @@ public class OpenRocketDocument implements ComponentChangeListener {
                                break;
                                
                        default:
-                               throw new RuntimeException("EEEK!");
+                               throw new BugException("illegal type="+type);
                        }
                        
                        if (desc != null)
index 5e8d8e9f960d5dff70c094116d7d759b6d0f324d..9867f2dd4c254e77f8f3630b90e619c6506ad68d 100644 (file)
@@ -18,6 +18,7 @@ import net.sf.openrocket.simulation.SimulationConditions;
 import net.sf.openrocket.simulation.SimulationListener;
 import net.sf.openrocket.simulation.exception.SimulationException;
 import net.sf.openrocket.simulation.exception.SimulationListenerException;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 
 
@@ -250,7 +251,7 @@ public class Simulation implements ChangeSource, Cloneable {
                                l = (SimulationListener)c.newInstance();
                        } catch (Exception e) {
                                throw new SimulationListenerException("Could not instantiate listener of " +
-                                               "class: " + className);
+                                               "class: " + className, e);
                        }
                        simulator.addSimulationListener(l);
                }
@@ -347,7 +348,7 @@ public class Simulation implements ChangeSource, Cloneable {
 
                
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("Clone not supported, BUG", e);
+                       throw new BugException("Clone not supported, BUG", e);
                }
        }
        
index 3a817ca529c9ed8eaaccf0973245ed29acb3acb1..7e1186c1e21222a8882737ba7ca5a6c641987b72 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.document;
 
+import net.sf.openrocket.util.BugException;
+
 public class StorageOptions implements Cloneable {
        
        public static final double SIMULATION_DATA_NONE = Double.POSITIVE_INFINITY;
@@ -45,7 +47,7 @@ public class StorageOptions implements Cloneable {
                try {
                        return (StorageOptions)super.clone();
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("CloneNotSupportedException?!?", e);
+                       throw new BugException("CloneNotSupportedException?!?", e);
                }
        }
 }
index ee2f94106d5271e01515c59a04dd79103cf1788e..113bc690eb74f48e316a36eda28aaa7ad69ac6dc 100644 (file)
@@ -52,11 +52,6 @@ public abstract class RocketLoader {
                        throw e;
                } catch (IOException e) {
                        throw new RocketLoadException("I/O error: " + e.getMessage());
-               } catch (Exception e) {
-                       throw new RocketLoadException("An unknown error occurred.  Please report a bug.", e);
-               } catch (Throwable e) {
-                       throw new RocketLoadException("A serious error occurred and the software may be "
-                                       + "unstable.  Save your designs and restart OpenRocket.", e);
                }
        }
 
index 3b7b23d955888e5d0fd97c32967a79b8fd99830a..8eb3a8004331b92379a39cef57275de675e5034a 100644 (file)
@@ -67,6 +67,7 @@ import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.SimulationConditions;
 import net.sf.openrocket.simulation.FlightEvent.Type;
 import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.LineStyle;
 import net.sf.openrocket.util.Reflection;
@@ -179,7 +180,7 @@ class DocumentConfig {
                        constructors.put("stage", Stage.class.getConstructor(new Class<?>[0]));
                        
                } catch (NoSuchMethodException e) {
-                       throw new RuntimeException(
+                       throw new BugException(
                                        "Error in constructing the 'constructors' HashMap.");
                }
        }
@@ -665,11 +666,11 @@ class ComponentHandler extends ElementHandler {
                try {
                        c = constructor.newInstance();
                } catch (InstantiationException e) {
-                       throw new RuntimeException("Error constructing component.", e);
+                       throw new BugException("Error constructing component.", e);
                } catch (IllegalAccessException e) {
-                       throw new RuntimeException("Error constructing component.", e);
+                       throw new BugException("Error constructing component.", e);
                } catch (InvocationTargetException e) {
-                       throw new RuntimeException("Error constructing component.", e);
+                       throw Reflection.handleInvocationTargetException(e);
                }
 
                parent.addChild(c);
index 6a13069b2fa1c85561ca82643159ff407b483da6..e0499395ea88f9f2f4257191d0d4adfe45a44820 100644 (file)
@@ -23,6 +23,7 @@ import net.sf.openrocket.simulation.FlightData;
 import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.SimulationConditions;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Pair;
 import net.sf.openrocket.util.Prefs;
@@ -213,7 +214,7 @@ public class OpenRocketSaver extends RocketSaver {
                Reflection.Method m = Reflection.findMethod(METHOD_PACKAGE, component, METHOD_SUFFIX,
                                "getElements", RocketComponent.class);
                if (m==null) {
-                       throw new RuntimeException("Unable to find saving class for component "+
+                       throw new BugException("Unable to find saving class for component "+
                                        component.getComponentName());
                }
 
index 64e55895db03c93ee5b40368744600a520ce480e..2d36896e8d1b53c7130241ad945ca33395be889b 100644 (file)
@@ -12,6 +12,7 @@ import net.sf.openrocket.rocketcomponent.ComponentAssembly;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.LineStyle;
 
 
@@ -94,7 +95,7 @@ public class RocketComponentSaver {
                        str += " type=\"bulk\"";
                        break;
                default:
-                       throw new RuntimeException("Unknown material type: " + mat.getType());
+                       throw new BugException("Unknown material type: " + mat.getType());
                }
 
                return str + " density=\"" + mat.getDensity() + "\">" + RocketSaver.escapeXML(mat.getName()) + "</"+tag+">";
index ab68c336aacd2e562a567890b6dcee942abdb6ae..1e8c52d23eede6254b463b4916f14123eb1e515f 100644 (file)
@@ -11,7 +11,9 @@ import javax.swing.AbstractAction;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
+import net.sf.openrocket.util.Reflection;
 
 
 /**
@@ -94,9 +96,9 @@ public class BooleanModel extends AbstractAction implements ChangeListener {
                try {
                        return (Boolean)getMethod.invoke(source);
                } catch (IllegalAccessException e) {
-                       throw new RuntimeException("getMethod execution error for source "+source,e);
+                       throw new BugException("getMethod execution error for source "+source,e);
                } catch (InvocationTargetException e) {
-                       throw new RuntimeException("getMethod execution error for source "+source,e);
+                       throw Reflection.handleInvocationTargetException(e);
                }
        }
        
@@ -104,9 +106,9 @@ public class BooleanModel extends AbstractAction implements ChangeListener {
                try {
                        setMethod.invoke(source, new Object[] { (Boolean)b });
                } catch (IllegalAccessException e) {
-                       throw new RuntimeException("setMethod execution error for source "+source,e);
+                       throw new BugException("setMethod execution error for source "+source,e);
                } catch (InvocationTargetException e) {
-                       throw new RuntimeException("setMethod execution error for source "+source,e);
+                       throw Reflection.handleInvocationTargetException(e);
                }
        }
        
@@ -167,9 +169,9 @@ public class BooleanModel extends AbstractAction implements ChangeListener {
                try {
                        return (Boolean)getEnabled.invoke(source);
                } catch (IllegalAccessException e) {
-                       throw new RuntimeException("getEnabled execution error for source "+source,e);
+                       throw new BugException("getEnabled execution error for source "+source,e);
                } catch (InvocationTargetException e) {
-                       throw new RuntimeException("getEnabled execution error for source "+source,e);
+                       throw Reflection.handleInvocationTargetException(e);
                }
        }
        
index da0c7747b2e48aec26968f2f33501629cd08e37f..6616b81c9cac7b4e54a17181f4ba80cee9b0b398 100644 (file)
@@ -17,8 +17,10 @@ import javax.swing.event.ChangeListener;
 
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 import net.sf.openrocket.util.MathUtil;
+import net.sf.openrocket.util.Reflection;
 
 
 /**
@@ -589,11 +591,11 @@ public class DoubleModel implements ChangeListener, ChangeSource {
                try {
                        return (Double)getMethod.invoke(source)*multiplier;
                } catch (IllegalArgumentException e) {
-                       throw new RuntimeException("BUG: Unable to invoke getMethod of "+this, e);
+                       throw new BugException("BUG: Unable to invoke getMethod of "+this, e);
                } catch (IllegalAccessException e) {
-                       throw new RuntimeException("BUG: Unable to invoke getMethod of "+this, e);
+                       throw new BugException("BUG: Unable to invoke getMethod of "+this, e);
                } catch (InvocationTargetException e) {
-                       throw new RuntimeException("BUG: Unable to invoke getMethod of "+this, e);
+                       throw Reflection.handleInvocationTargetException(e);
                }
        }
        
@@ -614,13 +616,12 @@ public class DoubleModel implements ChangeListener, ChangeSource {
 
                try {
                        setMethod.invoke(source, v/multiplier);
-                       return;
                } catch (IllegalArgumentException e) {
-                       throw new RuntimeException("BUG: Unable to invoke setMethod of "+this, e);
+                       throw new BugException("BUG: Unable to invoke setMethod of "+this, e);
                } catch (IllegalAccessException e) {
-                       throw new RuntimeException("BUG: Unable to invoke setMethod of "+this, e);
+                       throw new BugException("BUG: Unable to invoke setMethod of "+this, e);
                } catch (InvocationTargetException e) {
-                       throw new RuntimeException("Setter method of "+this+" threw exception", e);
+                       throw Reflection.handleInvocationTargetException(e);
                }
        }
 
@@ -643,13 +644,12 @@ public class DoubleModel implements ChangeListener, ChangeSource {
                try {
                        return (Boolean)getAutoMethod.invoke(source);
                } catch (IllegalArgumentException e) {
-                       e.printStackTrace();
+                       throw new BugException("Method call failed", e);
                } catch (IllegalAccessException e) {
-                       e.printStackTrace();
+                       throw new BugException("Method call failed", e);
                } catch (InvocationTargetException e) {
-                       e.printStackTrace();
+                       throw Reflection.handleInvocationTargetException(e);
                }
-               return false;  // Should not occur
        }
        
        /**
@@ -662,18 +662,16 @@ public class DoubleModel implements ChangeListener, ChangeSource {
                        return;
                }
                
+               lastAutomatic = auto;
                try {
-                       lastAutomatic = auto;
                        setAutoMethod.invoke(source, auto);
-                       return;
                } catch (IllegalArgumentException e) {
-                       e.printStackTrace();
+                       throw new BugException(e);
                } catch (IllegalAccessException e) {
-                       e.printStackTrace();
+                       throw new BugException(e);
                } catch (InvocationTargetException e) {
-                       e.printStackTrace();
+                       throw Reflection.handleInvocationTargetException(e);
                }
-               fireStateChanged();  // Should not occur
        }
        
 
index 0e141a65ab9b5f5227f7770d5cd6662afe5d2b23..20c459e78b61ec6fc1fa939f536b519332811249 100644 (file)
@@ -76,6 +76,10 @@ public class EnumModel<T extends Enum<T>> extends AbstractListModel
 
        @Override
        public void setSelectedItem(Object item) {
+               if (item == null) {
+                       // Clear selection - huh?
+                       return;
+               }
                if (item instanceof String) {
                        if (currentValue != null)
                                setMethod.invoke(source, (Object)null);
index 6800e0de670682c20a20df1c51b89bc786967706..60658b3fe921b686a21e7d3c5d2c329635fe947e 100644 (file)
@@ -9,7 +9,9 @@ import javax.swing.SpinnerNumberModel;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
+import net.sf.openrocket.util.Reflection;
 
 
 public class IntegerModel implements ChangeListener {
@@ -149,13 +151,12 @@ public class IntegerModel implements ChangeListener {
                try {
                        return (Integer)getMethod.invoke(source);
                } catch (IllegalArgumentException e) {
-                       e.printStackTrace();
+                       throw new BugException(e);
                } catch (IllegalAccessException e) {
-                       e.printStackTrace();
+                       throw new BugException(e);
                } catch (InvocationTargetException e) {
-                       e.printStackTrace();
+                       throw Reflection.handleInvocationTargetException(e);
                }
-               return lastValue;  // Should not occur
        }
        
        /**
@@ -164,15 +165,13 @@ public class IntegerModel implements ChangeListener {
        public void setValue(int v) {
                try {
                        setMethod.invoke(source, v);
-                       return;
                } catch (IllegalArgumentException e) {
-                       e.printStackTrace();
+                       throw new BugException(e);
                } catch (IllegalAccessException e) {
-                       e.printStackTrace();
+                       throw new BugException(e);
                } catch (InvocationTargetException e) {
-                       e.printStackTrace();
+                       throw Reflection.handleInvocationTargetException(e);
                }
-               fireStateChanged();  // Should not occur
        }
 
        
index be8df36eb4a762492949e8a71127c2dc1ca2f404..1defc447e422bfbdd418523f19e4ccb9e19210ea 100644 (file)
@@ -80,6 +80,11 @@ public class MaterialModel extends AbstractListModel implements
 
        @Override
        public void setSelectedItem(Object item) {
+               if (item == null) {
+                       // Clear selection - huh?
+                       return;
+               }
+
                if (item == CUSTOM) {
                        
                        // Open custom material dialog in the future, after combo box has closed
index 92e8473948e0f5aa6214d40f928e359078b2d615..5c01348747136b6b51432686772c313d490a34de 100644 (file)
@@ -63,6 +63,10 @@ public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
 
        @Override
        public void setSelectedItem(Object item) {
+               if (item == null) {
+                       // Clear selection - huh?
+                       return;
+               }
                if (item == EDIT) {
                        
                        // Open edit dialog in the future, after combo box has closed
@@ -76,8 +80,9 @@ public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
 
                        return;
                }
-               if (!(item instanceof ID))
-                       return;
+               if (!(item instanceof ID)) {
+                       throw new IllegalArgumentException("MotorConfigurationModel item="+item);
+               }
                
                ID idObject = (ID) item;
                config.setMotorConfigurationID(idObject.getID());
index 0be6b6d6947605e0274fcf3fcd717f0401b3b0f3..5d3f42a32143e96dd2b32558bfe8f189591c3c9b 100644 (file)
@@ -12,6 +12,8 @@ import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.Map;
 
+import net.sf.openrocket.util.BugException;
+
 /**
  * A label of a URL that is clickable.  Clicking the URL will launch the URL in
  * the default browser if the Desktop class is supported.
@@ -58,7 +60,7 @@ public class URLLabel extends SelectableLabel {
                                        try {
                                                d.browse(new URI(url));
                                        } catch (URISyntaxException e1) {
-                                               throw new RuntimeException("BUG: Illegal URL: " + url, e1);
+                                               throw new BugException("BUG: Illegal URL: " + url, e1);
                                        } catch (IOException e1) {
                                                System.err.println("Unable to launch browser:");
                                                e1.printStackTrace();
index 0ad6c93ac08d87f9b14699f8cbf148a8359a63fb..11c4e2d62449368d21e2d50db5d9a372638cff2b 100644 (file)
@@ -14,8 +14,10 @@ import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Prefs;
+import net.sf.openrocket.util.Reflection;
 
 /**
  * A dialog that contains the configuration elements of one component.
@@ -108,17 +110,17 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
                        try {
                                return (RocketComponentConfig) c.newInstance(component);
                        } catch (InstantiationException e) {
-                               throw new RuntimeException("BUG in constructor reflection",e);
+                               throw new BugException("BUG in constructor reflection",e);
                        } catch (IllegalAccessException e) {
-                               throw new RuntimeException("BUG in constructor reflection",e);
+                               throw new BugException("BUG in constructor reflection",e);
                        } catch (InvocationTargetException e) {
-                               throw new RuntimeException("BUG in constructor reflection",e);
+                               throw Reflection.handleInvocationTargetException(e);
                        }
                }
                
                // Should never be reached, since RocketComponentConfig should catch all
                // components without their own configurator.
-               throw new RuntimeException("Unable to find any configurator for "+component);
+               throw new BugException("Unable to find any configurator for "+component);
        }
 
        /**
index 7cfc1bd6fe6c8c859ea124c899413324ecefb46d..7d266371d96a26c904aa41c4ade647fcfb773153 100644 (file)
@@ -23,6 +23,7 @@ import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
 import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.dialogs.MotorChooserDialog;
 import net.sf.openrocket.motor.Motor;
@@ -123,10 +124,24 @@ public class MotorConfig extends JPanel {
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin,"gap rel rel");
                
-               panel.add(new JLabel("seconds"),"wrap paragraph");
+               panel.add(new JLabel("seconds"),"wrap unrel");
 
 
                
+               // Check stage count
+               RocketComponent c = (RocketComponent)mount;
+               c = c.getRocket();
+               int stages = c.getChildCount();
+               
+               if (stages == 1) {
+                       panel.add(new StyledLabel("The current design has only one stage.  " +
+                                       "Stages can be added by clicking \"New stage\".", -1), 
+                                       "spanx, right, wrap para");
+               } else {
+                       panel.add(new StyledLabel("The current design has " + stages + " stages.", -1), 
+                                       "skip 1, spanx, wrap para");
+               }
+               
                
                // Select etc. buttons
                button = new JButton("Select motor");
index f589dedc518903fd7c084536ccd943822fff403b..3a11c74b86da09054bd0ccbd9fd3ba51949cb736 100644 (file)
@@ -210,7 +210,13 @@ public class RingComponentConfig extends RocketComponentConfig {
                                ((RingComponent) component).setRadialPosition(0.0);
                        }
                });
-               panel.add(button,"spanx, right");
+               panel.add(button,"spanx, right, wrap para");
+               
+               
+               DescriptionArea note = new DescriptionArea(2);
+               note.setText("Note: An inner tube will not affect the aerodynamics" +
+                               " of the rocket even if it is located outside of the body tube.");
+               panel.add(note, "spanx, growx");
                
                
                return panel;
index b5b44b103c88766874519400a6db0b309d9dc5dd..7f397810078e132a143824f17b960e4fdb5d4c76 100644 (file)
@@ -28,6 +28,7 @@ import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.communication.BugReporter;
 import net.sf.openrocket.gui.components.SelectableLabel;
 import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.JarUtil;
 import net.sf.openrocket.util.Prefs;
@@ -288,7 +289,7 @@ public class BugReportDialog extends JDialog {
                        text = URLEncoder.encode(text, "UTF-8");
                        version = URLEncoder.encode(Prefs.getVersion(), "UTF-8");
                } catch (UnsupportedEncodingException e) {
-                       throw new RuntimeException(e);
+                       throw new BugException(e);
                }
                
                
index 13a80c075b1842f27796bddb7c9bf9bed91b892f..706f9aa4bf9a06dcc36a6c085e79fb2dba89b5a1 100644 (file)
@@ -27,6 +27,7 @@ import javax.swing.JScrollPane;
 import javax.swing.ListSelectionModel;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.JarUtil;
 
@@ -160,7 +161,7 @@ public class ExampleDesignDialog extends JDialog {
                                designs[i] = new ExampleDesign(files[i].toURI().toURL(), 
                                                name.substring(0, name.length()-4));
                        } catch (MalformedURLException e) {
-                               throw new RuntimeException(e);
+                               throw new BugException(e);
                        }
                }
                return designs;
@@ -185,7 +186,7 @@ public class ExampleDesignDialog extends JDialog {
                        fileUrl = file.toURI().toURL();
                } catch (MalformedURLException e1) {
                        e1.printStackTrace();
-                       throw new RuntimeException(e1);
+                       throw new BugException(e1);
                }
                
                // Iterate over JAR entries searching for designs
index 10759a69f3e7e62cde008ed600857a5c8fd47bd0..19ad7fe213c326135e16bf30c7d64b92d7519f65 100644 (file)
@@ -4,6 +4,7 @@ import java.awt.Font;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStreamReader;
 
 import javax.swing.JButton;
@@ -46,7 +47,7 @@ public class LicenseDialog extends JDialog {
                        }
                        licenseText = sb.toString();
                        
-               } catch (Exception e) {
+               } catch (IOException e) {
 
                        licenseText = DEFAULT_LICENSE_TEXT;
                        
index f288004f40f5d36d4d5281350076b030eab6399e..02bcfec19bb9b72cd6ea466525b76edac30b1a22 100644 (file)
@@ -7,6 +7,7 @@ import java.util.Collections;
 import java.util.List;
 
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -20,6 +21,8 @@ import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Icons;
 
 public class UpdateInfoDialog extends JDialog {
+       
+       private final JCheckBox remind;
 
        public UpdateInfoDialog(UpdateInfo info) {
                super((Window)null, "OpenRocket update available", ModalityType.APPLICATION_MODAL);
@@ -56,6 +59,11 @@ public class UpdateInfoDialog extends JDialog {
                                "gaptop para, alignx 50%, wrap unrel");
                panel.add(new URLLabel(AboutDialog.OPENROCKET_URL), "alignx 50%, wrap para");
                
+               remind = new JCheckBox("Remind me later");
+               remind.setToolTipText("Show this update also the next time you start OpenRocket");
+               remind.setSelected(true);
+               panel.add(remind);
+               
                JButton button = new JButton("Close");
                button.addActionListener(new ActionListener() {
                        @Override
@@ -63,7 +71,7 @@ public class UpdateInfoDialog extends JDialog {
                                UpdateInfoDialog.this.dispose();
                        }
                });
-               panel.add(button, "right");
+               panel.add(button, "right, gapright para");
                
                this.add(panel);
                
@@ -72,4 +80,9 @@ public class UpdateInfoDialog extends JDialog {
                GUIUtil.setDisposableDialogOptions(this, button);
        }
        
+       
+       public boolean isReminderSelected() {
+               return remind.isSelected();
+       }
+       
 }
index f2ed0ef2ab2579d0f2ae5cc76e7a01438c16c4dd..0f46cfe9772b8d759117e4edcd0dda7881c15a99 100644 (file)
@@ -259,6 +259,10 @@ public class PreferencesDialog extends JDialog {
                }
                @Override
                public void setSelectedItem(Object item) {
+                       if (item == null) {
+                               // Clear selection - huh?
+                               return;
+                       }
                        if (!(item instanceof Unit)) {
                                throw new IllegalArgumentException("Illegal argument "+item);
                        }
@@ -297,6 +301,10 @@ public class PreferencesDialog extends JDialog {
                
                @Override
                public void setSelectedItem(Object item) {
+                       if (item == null) {
+                               // Clear selection - huh?
+                               return;
+                       }
                        if (!(item instanceof String)) {
                                throw new IllegalArgumentException("Illegal argument "+item);
                        }
@@ -347,6 +355,10 @@ public class PreferencesDialog extends JDialog {
                
                @Override
                public void setSelectedItem(Object item) {
+                       if (item == null) {
+                               // Clear selection - huh?
+                               return;
+                       }
                        if (!(item instanceof String)) {
                                throw new IllegalArgumentException("Illegal argument "+item);
                        }
@@ -442,7 +454,13 @@ public class PreferencesDialog extends JDialog {
                                        "You are running the latest version of OpenRocket.", 
                                        "No updates available", JOptionPane.INFORMATION_MESSAGE, null);
                } else {
-                       new UpdateInfoDialog(info).setVisible(true);
+                       UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
+                       infoDialog.setVisible(true);
+                       if (infoDialog.isReminderSelected()) {
+                               Prefs.putString(Prefs.LAST_UPDATE, "");
+                       } else {
+                               Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
+                       }
                }
                
        }
index bd6e1552bb7279646d652a0e18ce7ae260de7ce5..a55137fc57d1f3787d19bbcaa9bf10905b12aa54 100644 (file)
@@ -87,6 +87,7 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.OpenFileWorker;
@@ -874,16 +875,16 @@ public class BasicFrame extends JFrame {
 
                        } else {
 
-                               throw new RuntimeException("Unknown error when opening file", e);
+                               throw new BugException("Unknown error when opening file", e);
 
                        }
 
                } catch (InterruptedException e) {
-                       throw new RuntimeException("EDT was interrupted", e);
+                       throw new BugException("EDT was interrupted", e);
                }
                
                if (doc == null) {
-                       throw new RuntimeException("BUG: Document loader returned null");
+                       throw new BugException("BUG: Document loader returned null");
                }
                
                
@@ -1004,11 +1005,11 @@ public class BasicFrame extends JFrame {
                                        e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
                        return false;
                        } else {
-                               throw new RuntimeException("Unknown error when saving file", e);
+                               throw new BugException("Unknown error when saving file", e);
                        }
                        
                } catch (InterruptedException e) {
-                       throw new RuntimeException("EDT was interrupted", e);
+                       throw new BugException("EDT was interrupted", e);
                }
            
            return saved;
@@ -1262,8 +1263,14 @@ public class BasicFrame extends JFrame {
                                        if (info != null && info.getLatestVersion() != null &&
                                                        !current.equals(info.getLatestVersion()) &&
                                                        !last.equals(info.getLatestVersion())) {
-                                               Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
-                                               new UpdateInfoDialog(info).setVisible(true);
+                                               
+                                               UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
+                                               infoDialog.setVisible(true);
+                                               if (infoDialog.isReminderSelected()) {
+                                                       Prefs.putString(Prefs.LAST_UPDATE, "");
+                                               } else {
+                                                       Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
+                                               }
                                        }
                                }
                                count--;
index a8072de47e72be4d0ac68b6dbd28b75d7e2d3be1..8e67b6a599655d80c1fa0e75bb6cdfc2fbfb8f25 100644 (file)
@@ -6,6 +6,7 @@ import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 
 import javax.swing.Icon;
 import javax.swing.JButton;
@@ -47,8 +48,10 @@ import net.sf.openrocket.rocketcomponent.Streamer;
 import net.sf.openrocket.rocketcomponent.Transition;
 import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
 import net.sf.openrocket.rocketcomponent.TubeCoupler;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Pair;
 import net.sf.openrocket.util.Prefs;
+import net.sf.openrocket.util.Reflection;
 
 /**
  * A component that contains addition buttons to add different types of rocket components
@@ -393,9 +396,14 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                        RocketComponent component;
                        try {
                                component = (RocketComponent)constructor.newInstance();
-                       } catch (Exception e) {
-                               throw new RuntimeException("Could not construct new instance of class "+
+                       } catch (InstantiationException e) {
+                               throw new BugException("Could not construct new instance of class "+
                                                constructor,e);
+                       } catch (IllegalAccessException e) {
+                               throw new BugException("Could not construct new instance of class "+
+                                               constructor,e);
+                       } catch (InvocationTargetException e) {
+                               throw Reflection.handleInvocationTargetException(e);
                        }
                        
                        // Next undo position is set by opening the configuration dialog
index 238ca3225e9ebc5ec5e21414c2a54ab563baa9ec..760bbabd22d2ec8c53e0c2a001bedff5a97404ad 100644 (file)
@@ -389,6 +389,8 @@ public class SimulationRunDialog extends JDialog {
                                
                        } else if (t instanceof Exception) {
                                
+                               // TODO: MEDIUM: Check the exception handling here...
+                               
                                DetailDialog.showDetailedMessageDialog(SimulationRunDialog.this, 
                                                new Object[] {
                                                "An exception occurred during the simulation:",
index 98f8a41f14f0f76c5e13fc996cb9f35d18f90817..3f97ad36d18f4d6e37fa188501046898c2f6e67e 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.gui.plot;
 
+import net.sf.openrocket.util.BugException;
+
 public class Axis implements Cloneable {
 
        private double minValue = Double.NaN;
@@ -45,7 +47,7 @@ public class Axis implements Cloneable {
                        return (Axis) super.clone();
                        
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("BUG! Could not clone().");
+                       throw new BugException("BUG! Could not clone().");
                }
        }
        
index 55398736e62d6a7f0b6db16066de7b26952d4255..f5f304961ea4264eb46424bd810b2c04f204e74a 100644 (file)
@@ -9,6 +9,7 @@ import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.FlightDataBranch.Type;
 import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Pair;
 
@@ -733,7 +734,7 @@ public class PlotConfiguration implements Cloneable {
                        
                        
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("BUG! Could not clone().");
+                       throw new BugException("BUG! Could not clone().");
                }
        }
        
index d84fed9b55ebebf385bc0c0cc496abf88b32d5d9..24bb3a6617fbc2cc1fd8e593017fc5091d389c9a 100644 (file)
@@ -34,6 +34,7 @@ import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Pair;
@@ -341,7 +342,7 @@ public class PlotDialog extends JDialog {
                                        double t2 = time.get(tindex+1);
                                        
                                        if ((t1 > t) || (t2 < t)) {
-                                               throw new RuntimeException("BUG: t1="+t1+" t2="+t2+" t="+t);
+                                               throw new BugException("BUG: t1="+t1+" t2="+t2+" t="+t);
                                        }
                                        
                                        if (MathUtil.equals(t1, t2)) {
index 776728dcfed53d2266ca08b433e25c7fe7582a92..c19b5e8fe8403236bdbe1f253a0411ae0d37bf48 100644 (file)
@@ -25,6 +25,7 @@ import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.LineStyle;
 import net.sf.openrocket.util.MathUtil;
@@ -438,7 +439,7 @@ public class RocketFigure extends AbstractScaleFigure {
                        break;
                        
                default:
-                       throw new RuntimeException("Unknown figure type = "+type);
+                       throw new BugException("Unknown figure type = "+type);
                }
                
                if (m == null) {
@@ -537,7 +538,7 @@ public class RocketFigure extends AbstractScaleFigure {
                        return new Rectangle2D.Double(-maxR,-maxR,2*maxR,2*maxR);
                        
                default:
-                       throw new RuntimeException("Illegal figure type = "+type);
+                       throw new BugException("Illegal figure type = "+type);
                }
        }
 
index caa285156e3bc5467ad95f681ebba6c5ad9ef0bf..aa46b68240dd688d3d1ac060d662d1162ff3e123 100644 (file)
@@ -28,6 +28,7 @@ import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.unit.Tick;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
 
 
 
@@ -144,7 +145,7 @@ public class ScaleScrollPane extends JScrollPane
        
        public void setFitting(boolean fit) {
                if (fit && !allowFit) {
-                       throw new RuntimeException("Attempting to fit figure not allowing fit.");
+                       throw new BugException("Attempting to fit figure not allowing fit.");
                }
                this.fit = fit;
                if (fit) {
index ce746d332ab24b434557bd1f28f8fb14ffdb0c77..7d3be842fba2f055f3211843e92d6a4b847ac9c2 100644 (file)
@@ -6,6 +6,7 @@ import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
@@ -282,7 +283,7 @@ public abstract class Motor implements Comparable<Motor> {
                        avgTime *= time/(DIVISIONS+1);
                        
                        if (Double.isNaN(avgTime))
-                               throw new RuntimeException("Calculated avg. time is NaN for motor "+this);
+                               throw new BugException("Calculated avg. time is NaN for motor "+this);
 
                }
                return avgTime;
@@ -315,7 +316,7 @@ public abstract class Motor implements Comparable<Motor> {
                                avgThrust /= points;
                        
                        if (Double.isNaN(avgThrust))
-                               throw new RuntimeException("Calculated average thrust is NaN for motor "+this);
+                               throw new BugException("Calculated average thrust is NaN for motor "+this);
                }
                return avgThrust;
        }
@@ -346,7 +347,7 @@ public abstract class Motor implements Comparable<Motor> {
                        }
                        
                        if (Double.isNaN(totalImpulse))
-                               throw new RuntimeException("Calculated total impulse is NaN for motor "+this);
+                               throw new BugException("Calculated total impulse is NaN for motor "+this);
                }
                return totalImpulse;
        }
index 3d70493dedee977072218c54872efe52d1ddbf42..b0f2aa931ce3ab14f3c96638ee5f4e769b7c06ac 100644 (file)
@@ -20,7 +20,11 @@ public class CenteringRing extends RadiusRingComponent {
                        // Component can be parentless if disattached from rocket
                        if (this.getParent() != null) {
                                for (RocketComponent sibling: this.getParent().getChildren()) {
-                                       if (!(sibling instanceof RadialParent))  // Excludes itself
+                                       /*
+                                        * Only InnerTubes are considered when determining the automatic
+                                        * inner radius (for now).
+                                        */
+                                       if (!(sibling instanceof InnerTube))  // Excludes itself
                                                continue;
                                        
                                        double pos1 = this.toRelative(Coordinate.NUL, sibling)[0].x;
@@ -28,7 +32,6 @@ public class CenteringRing extends RadiusRingComponent {
                                        if (pos2 < 0 || pos1 > sibling.getLength())
                                                continue;
                                        
-                                       // TODO: CRITICAL: ClassCastException below:
                                        innerRadius = Math.max(innerRadius, ((InnerTube)sibling).getOuterRadius());
                                }
                                innerRadius = Math.min(innerRadius, getOuterRadius());
index f5c3116003b2281bf768738857bb510b67ffb033..88fb6d8aa81651b51f803e11e014c41d6cf5a876 100644 (file)
@@ -13,6 +13,7 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.EventListenerList;
 
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
@@ -393,7 +394,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi
                        rocket.addComponentChangeListener(config);
                        return config;
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("BUG: clone not supported!",e);
+                       throw new BugException("BUG: clone not supported!",e);
                }
        }
 
index 29f146be617e9b68bbc1a48713001972e826106d..af74501b9a9ca7163c88e79e29eefd0bfa0eb1a6 100644 (file)
@@ -13,6 +13,7 @@ import java.util.UUID;
 
 import javax.swing.event.ChangeListener;
 
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.LineStyle;
@@ -307,7 +308,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                try {
                        clone = (RocketComponent)this.clone();
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("CloneNotSupportedException encountered, " +
+                       throw new BugException("CloneNotSupportedException encountered, " +
                                        "report a bug!",e);
                }
 
@@ -778,7 +779,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                                break;
                                
                        default:
-                               throw new RuntimeException("Unknown relative positioning type of component"+
+                               throw new BugException("Unknown relative positioning type of component"+
                                                component+": "+component.relativePosition);
                        }
 
@@ -1113,9 +1114,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                        return null;
                int pos = parent.getChildPosition(this);
                if (pos < 0) {
-                       throw new IllegalStateException("Inconsistent internal state: " +
-                                       "this="+this+" parent="+parent+" parent.children="+
-                                       parent.children.toString());
+                       StringBuffer sb = new StringBuffer();
+                       sb.append("Inconsistent internal state: ");
+                       sb.append("this=").append(this).append('[').append(System.identityHashCode(this)).append(']');
+                       sb.append(" parent.children=[");
+                       for (int i=0; i < parent.children.size(); i++) {
+                               RocketComponent c = parent.children.get(i);
+                               sb.append(c).append('[').append(System.identityHashCode(c)).append(']');
+                               if (i < parent.children.size()-1)
+                                       sb.append(", ");
+                       }
+                       throw new IllegalStateException(sb.toString());
                }
                assert(pos >= 0);
                if (pos == 0)
index 2e7e4cf8ac9fd61a92b3b71b20703e55e5758f62..6c048c6fe3b32b7b146e403d4197cca84e66781a 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Prefs;
 
@@ -22,7 +23,7 @@ public class ShockCord extends MassObject {
        
        public void setMaterial(Material m) {
                if (m.getType() != Material.Type.LINE)
-                       throw new RuntimeException("Attempting to set non-linear material.");
+                       throw new BugException("Attempting to set non-linear material.");
                if (material.equals(m))
                        return;
                this.material = m;
index 8b79bfbc9ef303e4db2618dcafb1e58b2e9d8501..da407772aba8b324517ced8167bc80ecd165adec 100644 (file)
@@ -9,6 +9,7 @@ import javax.swing.event.ChangeListener;
 import net.sf.openrocket.aerodynamics.AtmosphericModel;
 import net.sf.openrocket.aerodynamics.ExtendedISAModel;
 import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 import net.sf.openrocket.util.MathUtil;
 
@@ -321,7 +322,7 @@ public class SimulationConditions implements ChangeSource, Cloneable {
                        copy.listeners = new ArrayList<ChangeListener>();
                        return copy;
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException(e);
+                       throw new BugException(e);
                }
        }
        
index 4d05cbf160007494b1db3fd8ed527700bf994bd1..4ebf020bb43b04a94237dce5c77cc0d72886d8a2 100644 (file)
@@ -8,6 +8,7 @@ import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.aerodynamics.WindSimulator;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 
 
@@ -66,7 +67,7 @@ public class SimulationStatus implements Cloneable {
                try {
                        return (SimulationStatus) super.clone();
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("BUG:  CloneNotSupportedException?!?",e);
+                       throw new BugException("BUG:  CloneNotSupportedException?!?",e);
                }
        }
 }
diff --git a/src/net/sf/openrocket/util/BugException.java b/src/net/sf/openrocket/util/BugException.java
new file mode 100644 (file)
index 0000000..94a2834
--- /dev/null
@@ -0,0 +1,25 @@
+package net.sf.openrocket.util;
+
+/**
+ * Thrown when a bug is noticed.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class BugException extends FatalException {
+
+       public BugException() {
+       }
+
+       public BugException(String message) {
+               super(message);
+       }
+
+       public BugException(Throwable cause) {
+               super(cause);
+       }
+
+       public BugException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+}
diff --git a/src/net/sf/openrocket/util/ConfigurationException.java b/src/net/sf/openrocket/util/ConfigurationException.java
new file mode 100644 (file)
index 0000000..692b3ac
--- /dev/null
@@ -0,0 +1,26 @@
+package net.sf.openrocket.util;
+
+/**
+ * An exception to be thrown when a fatal problem with the environment
+ * is encountered (for example some file cannot be found).
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class ConfigurationException extends FatalException {
+
+       public ConfigurationException() {
+       }
+
+       public ConfigurationException(String message) {
+               super(message);
+       }
+
+       public ConfigurationException(Throwable cause) {
+               super(cause);
+       }
+
+       public ConfigurationException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+}
diff --git a/src/net/sf/openrocket/util/FatalException.java b/src/net/sf/openrocket/util/FatalException.java
new file mode 100644 (file)
index 0000000..b50feef
--- /dev/null
@@ -0,0 +1,28 @@
+package net.sf.openrocket.util;
+
+/**
+ * A superclass for all types of fatal error conditions.  This class is
+ * abstract so only subclasses can be used.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ * @see BugException
+ * @see ConfigurationException
+ */
+public abstract class FatalException extends RuntimeException {
+
+       public FatalException() {
+       }
+
+       public FatalException(String message) {
+               super(message);
+       }
+
+       public FatalException(Throwable cause) {
+               super(cause);
+       }
+
+       public FatalException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+}
index 00efe3a40c51d9d40f309fee24e3b76d6a66063e..e94a39766e6237306e42f241549a6ccfc0394718 100644 (file)
@@ -109,7 +109,7 @@ public class LinearInterpolator implements Cloneable {
                        other.sortMap = (TreeMap<Double,Double>)this.sortMap.clone();
                        return other;
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("CloneNotSupportedException?!",e);
+                       throw new BugException("CloneNotSupportedException?!",e);
                }
        }
 
index e95587b5c90906e3f78e5f199b92c3333d9eb7ca..9a562cb854e485e255b55d523805586e6127b233 100644 (file)
@@ -62,4 +62,10 @@ public class Pair<U,V> {
                return ((u != null) ? u.hashCode() : 0) + ((v != null) ? v.hashCode() : 0);
        }
        
+       
+       @Override
+       public String toString() {
+               return "[" + u + ";" + v + "]";
+       }
+       
 }
index 70a3e558e6542ed022b899f35e41864c5d4e8c61..eb2e3d4730dd8ecbc2b3776ec77d212b5faa2727 100644 (file)
@@ -142,7 +142,7 @@ public class Prefs {
                                        root.node(NODENAME).removeNode();
                                }
                        } catch (BackingStoreException e) {
-                               throw new RuntimeException("Unable to clear preference node",e);
+                               throw new BugException("Unable to clear preference node",e);
                        }
                }
                PREFNODE = root.node(NODENAME);
index 3c457caba5aa7c85508c9fe6969f6d31762cd1b5..ee2a2d25a779b6528692a29ded75a243944c396d 100644 (file)
@@ -135,7 +135,7 @@ public class Quaternion implements Cloneable {
                try {
                        return (Quaternion) super.clone();
                } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException("CloneNotSupportedException encountered");
+                       throw new BugException("CloneNotSupportedException encountered");
                }
        }
 
index 26c00beff5362640b3448f396cf92ed60cc87a55..d837a4971481928f68fd9cf7db5039000c0ead1c 100644 (file)
@@ -29,14 +29,13 @@ public class Reflection {
                        try {
                                return method.invoke(obj, args);
                        } catch (IllegalArgumentException e) {
-                               throw new RuntimeException("Error while invoking method '"+method+"'. "+
+                               throw new BugException("Error while invoking method '"+method+"'. "+
                                                "Please report this as a bug.",e);
                        } catch (IllegalAccessException e) {
-                               throw new RuntimeException("Error while invoking method '"+method+"'. "+
+                               throw new BugException("Error while invoking method '"+method+"'. "+
                                                "Please report this as a bug.",e);
                        } catch (InvocationTargetException e) {
-                               throw new RuntimeException("Error while invoking method '"+method+"'. "+
-                                               "Please report this as a bug.",e);
+                               throw Reflection.handleInvocationTargetException(e);
                        }
                }
                /**
@@ -55,6 +54,34 @@ public class Reflection {
        }
        
        
+       /**
+        * Handles an InvocationTargetException gracefully.  If the cause is an unchecked
+        * exception it is thrown, otherwise it is encapsulated in a BugException.
+        * <p>
+        * This method has a return type of Error in order to allow writing code like:
+        * <pre>throw Reflection.handleInvocationTargetException(e)</pre>
+        * This allows the compiler verifying that the call will never succeed correctly
+        * and ending that branch of execution.
+        * 
+        * @param e             the InvocationTargetException that occurred (not null).
+        * @return              never returns normally.
+        */
+       public static Error handleInvocationTargetException(InvocationTargetException e) {
+               Throwable cause = e.getCause();
+               if (cause == null) {
+                       throw new BugException("BUG: InvocationTargetException without cause", e);
+               }
+               if (cause instanceof RuntimeException) {
+                       throw (RuntimeException)cause;
+               }
+               if (cause instanceof Error) {
+                       throw (Error)cause;
+               }
+               throw new BugException("InvocationTargetException occurred", cause);
+       }
+       
+       
+       
        /**
         * Throws an exception if method not found.
         */
@@ -64,7 +91,7 @@ public class Reflection {
                Reflection.Method m = findMethod(ROCKETCOMPONENT_PACKAGE, componentClass, 
                                "", method, params);
                if (m == null) {
-                       throw new RuntimeException("Could not find method for componentClass="
+                       throw new BugException("Could not find method for componentClass="
                                        +componentClass+" method="+method);
                }
                return m;
@@ -145,18 +172,18 @@ public class Reflection {
                                }
                        } catch (ClassNotFoundException ignore) {
                        } catch (IllegalArgumentException e) {
-                               throw new RuntimeException("Construction of "+name+" failed",e);
+                               throw new BugException("Construction of "+name+" failed",e);
                        } catch (InstantiationException e) {
-                               throw new RuntimeException("Construction of "+name+" failed",e);
+                               throw new BugException("Construction of "+name+" failed",e);
                        } catch (IllegalAccessException e) {
-                               throw new RuntimeException("Construction of "+name+" failed",e);
+                               throw new BugException("Construction of "+name+" failed",e);
                        } catch (InvocationTargetException e) {
-                               throw new RuntimeException("Construction of "+name+" failed",e);
+                               throw Reflection.handleInvocationTargetException(e);
                        }
 
                        currentclass = currentclass.getSuperclass();
                }
-               throw new RuntimeException("Suitable constructor for component "+component+ 
+               throw new BugException("Suitable constructor for component "+component+ 
                                " not found");
        }
 }
index a4a65c46c4da0c4284f437c00b42906838676613..aeb68ad499b01649734eb894edb824f3aecfb6ce 100644 (file)
@@ -118,11 +118,11 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
                                        e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
                        return false;
                        } else {
-                               throw new RuntimeException("Unknown error when saving file", e);
+                               throw new BugException("Unknown error when saving file", e);
                        }
                        
                } catch (InterruptedException e) {
-                       throw new RuntimeException("EDT was interrupted", e);
+                       throw new BugException("EDT was interrupted", e);
                }
                
                return true;
index 0ae317b38584ed229fafa4d360ec03ce6d43127c..ab5c48ab7becc5d1c9f4b28cbc7b4134fb2f9a00 100644 (file)
@@ -16,6 +16,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import net.sf.openrocket.util.BugException;
+
 public class HttpURLConnectionMock extends HttpURLConnection {
 
        private static final URL MOCK_URL;
@@ -23,7 +25,7 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                try {
                        MOCK_URL = new URL("http://localhost/");
                } catch (MalformedURLException e) {
-                       throw new RuntimeException(e);
+                       throw new BugException(e);
                }
        }
        
diff --git a/test/net/sf/openrocket/util/ReflectionTest.java b/test/net/sf/openrocket/util/ReflectionTest.java
new file mode 100644 (file)
index 0000000..217332b
--- /dev/null
@@ -0,0 +1,50 @@
+package net.sf.openrocket.util;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.junit.Test;
+
+public class ReflectionTest {
+
+       @Test
+       public void textHandleInvocationTargetException() {
+               Throwable cause = null;
+               
+               try {
+                       cause = new InvocationTargetException(null);
+                       Reflection.handleInvocationTargetException((InvocationTargetException)cause);
+                       fail();
+               } catch (BugException e) {
+                       assertTrue(cause == e.getCause());
+               }
+               
+               try {
+                       cause = new IllegalStateException("Test");
+                       Reflection.handleInvocationTargetException(new InvocationTargetException(cause));
+                       fail();
+               } catch (IllegalStateException e) {
+                       assertTrue(cause == e);
+               }
+               
+               try {
+                       cause = new AbstractMethodError();
+                       Reflection.handleInvocationTargetException(new InvocationTargetException(cause));
+                       fail();
+               } catch (AbstractMethodError e) { 
+                       assertTrue(cause == e);
+               }
+               
+               try {
+                       cause = new IOException();
+                       Reflection.handleInvocationTargetException(new InvocationTargetException(cause));
+                       fail();
+               } catch (BugException e) { 
+                       assertTrue(cause == e.getCause());
+               }
+               
+       }
+       
+}