From: plaa Date: Sat, 28 Nov 2009 14:28:39 +0000 (+0000) Subject: Updates for 0.9.5 X-Git-Tag: upstream/1.0.0~8 X-Git-Url: https://git.gag.com/?p=debian%2Fopenrocket;a=commitdiff_plain;h=c72e1c03cc0d15e11368707c38721d506ce356b9 Updates for 0.9.5 git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@34 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/ChangeLog b/ChangeLog index 5967b47b..64c6e46a 100644 --- 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 diff --git a/ReleaseNotes b/ReleaseNotes index 698f5ca4..c6786057 100644 --- a/ReleaseNotes +++ b/ReleaseNotes @@ -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 ec071f93..79f2c962 100644 --- 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 diff --git a/build.properties b/build.properties index 0fa9bd66..cee4d6a1 100644 --- a/build.properties +++ b/build.properties @@ -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 index 00000000..e58ce2d4 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 index 00000000..648d9088 Binary files /dev/null and b/dists/OpenRocket-0.9.5.jar differ diff --git a/html/actions/updates.php b/html/actions/updates.php index 55e3e147..aceea793 100644 --- a/html/actions/updates.php +++ b/html/actions/updates.php @@ -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 diff --git a/releasing.txt b/releasing.txt index 63164c4f..fb139efc 100644 --- a/releasing.txt +++ b/releasing.txt @@ -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 diff --git a/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java b/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java index 5a6abcb0..fbc9b7c0 100644 --- a/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java +++ b/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java @@ -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?!?"); } } diff --git a/src/net/sf/openrocket/aerodynamics/AtmosphericConditions.java b/src/net/sf/openrocket/aerodynamics/AtmosphericConditions.java index c36c525f..d2e910ea 100644 --- a/src/net/sf/openrocket/aerodynamics/AtmosphericConditions.java +++ b/src/net/sf/openrocket/aerodynamics/AtmosphericConditions.java @@ -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!"); } } diff --git a/src/net/sf/openrocket/aerodynamics/FlightConditions.java b/src/net/sf/openrocket/aerodynamics/FlightConditions.java index 58d964e1..56712a2a 100644 --- a/src/net/sf/openrocket/aerodynamics/FlightConditions.java +++ b/src/net/sf/openrocket/aerodynamics/FlightConditions.java @@ -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); } } diff --git a/src/net/sf/openrocket/aerodynamics/WarningSet.java b/src/net/sf/openrocket/aerodynamics/WarningSet.java index 32355bc3..ead0625c 100644 --- a/src/net/sf/openrocket/aerodynamics/WarningSet.java +++ b/src/net/sf/openrocket/aerodynamics/WarningSet.java @@ -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 Warnings. 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 implements Cloneable { return newSet; } catch (CloneNotSupportedException e) { - throw new RuntimeException("CloneNotSupportedException occurred, report bug!",e); + throw new BugException("CloneNotSupportedException occurred, report bug!",e); } } diff --git a/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java b/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java index 3f0e4e79..c112a18a 100644 --- a/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java +++ b/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java @@ -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()); } diff --git a/src/net/sf/openrocket/communication/Communicator.java b/src/net/sf/openrocket/communication/Communicator.java index 24ed1f56..06c666b7 100644 --- a/src/net/sf/openrocket/communication/Communicator.java +++ b/src/net/sf/openrocket/communication/Communicator.java @@ -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); } } diff --git a/src/net/sf/openrocket/communication/UpdateInfo.java b/src/net/sf/openrocket/communication/UpdateInfo.java index 73e39633..a9b0d044 100644 --- a/src/net/sf/openrocket/communication/UpdateInfo.java +++ b/src/net/sf/openrocket/communication/UpdateInfo.java @@ -47,4 +47,9 @@ public class UpdateInfo { return (List>) updates.clone(); } + @Override + public String toString() { + return "UpdateInfo[version=" + latestVersion + "; updates=" + updates.toString() + "]"; + } + } diff --git a/src/net/sf/openrocket/communication/UpdateInfoRetriever.java b/src/net/sf/openrocket/communication/UpdateInfoRetriever.java index 082f2b9f..4fd07824 100644 --- a/src/net/sf/openrocket/communication/UpdateInfoRetriever.java +++ b/src/net/sf/openrocket/communication/UpdateInfoRetriever.java @@ -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) diff --git a/src/net/sf/openrocket/database/Databases.java b/src/net/sf/openrocket/database/Databases.java index cdf39c2e..efb8cd6c 100644 --- a/src/net/sf/openrocket/database/Databases.java +++ b/src/net/sf/openrocket/database/Databases.java @@ -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); } } } diff --git a/src/net/sf/openrocket/document/OpenRocketDocument.java b/src/net/sf/openrocket/document/OpenRocketDocument.java index 164f76da..83c4b0b7 100644 --- a/src/net/sf/openrocket/document/OpenRocketDocument.java +++ b/src/net/sf/openrocket/document/OpenRocketDocument.java @@ -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) diff --git a/src/net/sf/openrocket/document/Simulation.java b/src/net/sf/openrocket/document/Simulation.java index 5e8d8e9f..9867f2dd 100644 --- a/src/net/sf/openrocket/document/Simulation.java +++ b/src/net/sf/openrocket/document/Simulation.java @@ -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); } } diff --git a/src/net/sf/openrocket/document/StorageOptions.java b/src/net/sf/openrocket/document/StorageOptions.java index 3a817ca5..7e1186c1 100644 --- a/src/net/sf/openrocket/document/StorageOptions.java +++ b/src/net/sf/openrocket/document/StorageOptions.java @@ -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); } } } diff --git a/src/net/sf/openrocket/file/RocketLoader.java b/src/net/sf/openrocket/file/RocketLoader.java index ee2f9410..113bc690 100644 --- a/src/net/sf/openrocket/file/RocketLoader.java +++ b/src/net/sf/openrocket/file/RocketLoader.java @@ -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); } } diff --git a/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java b/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java index 3b7b23d9..8eb3a800 100644 --- a/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java +++ b/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java @@ -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); diff --git a/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java index 6a13069b..e0499395 100644 --- a/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java +++ b/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java @@ -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()); } diff --git a/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java b/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java index 64e55895..2d36896e 100644 --- a/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java +++ b/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java @@ -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()) + ""; diff --git a/src/net/sf/openrocket/gui/adaptors/BooleanModel.java b/src/net/sf/openrocket/gui/adaptors/BooleanModel.java index ab68c336..1e8c52d2 100644 --- a/src/net/sf/openrocket/gui/adaptors/BooleanModel.java +++ b/src/net/sf/openrocket/gui/adaptors/BooleanModel.java @@ -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); } } diff --git a/src/net/sf/openrocket/gui/adaptors/DoubleModel.java b/src/net/sf/openrocket/gui/adaptors/DoubleModel.java index da0c7747..6616b81c 100644 --- a/src/net/sf/openrocket/gui/adaptors/DoubleModel.java +++ b/src/net/sf/openrocket/gui/adaptors/DoubleModel.java @@ -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 } diff --git a/src/net/sf/openrocket/gui/adaptors/EnumModel.java b/src/net/sf/openrocket/gui/adaptors/EnumModel.java index 0e141a65..20c459e7 100644 --- a/src/net/sf/openrocket/gui/adaptors/EnumModel.java +++ b/src/net/sf/openrocket/gui/adaptors/EnumModel.java @@ -76,6 +76,10 @@ public class EnumModel> 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); diff --git a/src/net/sf/openrocket/gui/adaptors/IntegerModel.java b/src/net/sf/openrocket/gui/adaptors/IntegerModel.java index 6800e0de..60658b3f 100644 --- a/src/net/sf/openrocket/gui/adaptors/IntegerModel.java +++ b/src/net/sf/openrocket/gui/adaptors/IntegerModel.java @@ -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 } diff --git a/src/net/sf/openrocket/gui/adaptors/MaterialModel.java b/src/net/sf/openrocket/gui/adaptors/MaterialModel.java index be8df36e..1defc447 100644 --- a/src/net/sf/openrocket/gui/adaptors/MaterialModel.java +++ b/src/net/sf/openrocket/gui/adaptors/MaterialModel.java @@ -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 diff --git a/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java b/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java index 92e84739..5c013487 100644 --- a/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java +++ b/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java @@ -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()); diff --git a/src/net/sf/openrocket/gui/components/URLLabel.java b/src/net/sf/openrocket/gui/components/URLLabel.java index 0be6b6d6..5d3f42a3 100644 --- a/src/net/sf/openrocket/gui/components/URLLabel.java +++ b/src/net/sf/openrocket/gui/components/URLLabel.java @@ -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(); diff --git a/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java b/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java index 0ad6c93a..11c4e2d6 100644 --- a/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java +++ b/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java @@ -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); } /** diff --git a/src/net/sf/openrocket/gui/configdialog/MotorConfig.java b/src/net/sf/openrocket/gui/configdialog/MotorConfig.java index 7cfc1bd6..7d266371 100644 --- a/src/net/sf/openrocket/gui/configdialog/MotorConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/MotorConfig.java @@ -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"); diff --git a/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java b/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java index f589dedc..3a11c74b 100644 --- a/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java b/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java index b5b44b10..7f397810 100644 --- a/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java @@ -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); } diff --git a/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java b/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java index 13a80c07..706f9aa4 100644 --- a/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/ExampleDesignDialog.java @@ -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 diff --git a/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java b/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java index 10759a69..19ad7fe2 100644 --- a/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/LicenseDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java b/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java index f288004f..02bcfec1 100644 --- a/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java @@ -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(); + } + } diff --git a/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java b/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java index f2ed0ef2..0f46cfe9 100644 --- a/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java @@ -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()); + } } } diff --git a/src/net/sf/openrocket/gui/main/BasicFrame.java b/src/net/sf/openrocket/gui/main/BasicFrame.java index bd6e1552..a55137fc 100644 --- a/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -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--; diff --git a/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/src/net/sf/openrocket/gui/main/ComponentAddButtons.java index a8072de4..8e67b6a5 100644 --- a/src/net/sf/openrocket/gui/main/ComponentAddButtons.java +++ b/src/net/sf/openrocket/gui/main/ComponentAddButtons.java @@ -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 diff --git a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java index 238ca322..760bbabd 100644 --- a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java @@ -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:", diff --git a/src/net/sf/openrocket/gui/plot/Axis.java b/src/net/sf/openrocket/gui/plot/Axis.java index 98f8a41f..3f97ad36 100644 --- a/src/net/sf/openrocket/gui/plot/Axis.java +++ b/src/net/sf/openrocket/gui/plot/Axis.java @@ -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()."); } } diff --git a/src/net/sf/openrocket/gui/plot/PlotConfiguration.java b/src/net/sf/openrocket/gui/plot/PlotConfiguration.java index 55398736..f5f30496 100644 --- a/src/net/sf/openrocket/gui/plot/PlotConfiguration.java +++ b/src/net/sf/openrocket/gui/plot/PlotConfiguration.java @@ -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()."); } } diff --git a/src/net/sf/openrocket/gui/plot/PlotDialog.java b/src/net/sf/openrocket/gui/plot/PlotDialog.java index d84fed9b..24bb3a66 100644 --- a/src/net/sf/openrocket/gui/plot/PlotDialog.java +++ b/src/net/sf/openrocket/gui/plot/PlotDialog.java @@ -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)) { diff --git a/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java index 776728dc..c19b5e8f 100644 --- a/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java +++ b/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java @@ -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); } } diff --git a/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java b/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java index caa28515..aa46b682 100644 --- a/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java +++ b/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java @@ -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) { diff --git a/src/net/sf/openrocket/motor/Motor.java b/src/net/sf/openrocket/motor/Motor.java index ce746d33..7d3be842 100644 --- a/src/net/sf/openrocket/motor/Motor.java +++ b/src/net/sf/openrocket/motor/Motor.java @@ -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 { 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 { 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 { } 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; } diff --git a/src/net/sf/openrocket/rocketcomponent/CenteringRing.java b/src/net/sf/openrocket/rocketcomponent/CenteringRing.java index 3d70493d..b0f2aa93 100644 --- a/src/net/sf/openrocket/rocketcomponent/CenteringRing.java +++ b/src/net/sf/openrocket/rocketcomponent/CenteringRing.java @@ -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()); diff --git a/src/net/sf/openrocket/rocketcomponent/Configuration.java b/src/net/sf/openrocket/rocketcomponent/Configuration.java index f5c31160..88fb6d8a 100644 --- a/src/net/sf/openrocket/rocketcomponent/Configuration.java +++ b/src/net/sf/openrocket/rocketcomponent/Configuration.java @@ -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); } } diff --git a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 29f146be..af74501b 100644 --- a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -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) diff --git a/src/net/sf/openrocket/rocketcomponent/ShockCord.java b/src/net/sf/openrocket/rocketcomponent/ShockCord.java index 2e7e4cf8..6c048c6f 100644 --- a/src/net/sf/openrocket/rocketcomponent/ShockCord.java +++ b/src/net/sf/openrocket/rocketcomponent/ShockCord.java @@ -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; diff --git a/src/net/sf/openrocket/simulation/SimulationConditions.java b/src/net/sf/openrocket/simulation/SimulationConditions.java index 8b79bfbc..da407772 100644 --- a/src/net/sf/openrocket/simulation/SimulationConditions.java +++ b/src/net/sf/openrocket/simulation/SimulationConditions.java @@ -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(); return copy; } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); + throw new BugException(e); } } diff --git a/src/net/sf/openrocket/simulation/SimulationStatus.java b/src/net/sf/openrocket/simulation/SimulationStatus.java index 4d05cbf1..4ebf020b 100644 --- a/src/net/sf/openrocket/simulation/SimulationStatus.java +++ b/src/net/sf/openrocket/simulation/SimulationStatus.java @@ -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 index 00000000..94a28349 --- /dev/null +++ b/src/net/sf/openrocket/util/BugException.java @@ -0,0 +1,25 @@ +package net.sf.openrocket.util; + +/** + * Thrown when a bug is noticed. + * + * @author Sampo Niskanen + */ +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 index 00000000..692b3ac1 --- /dev/null +++ b/src/net/sf/openrocket/util/ConfigurationException.java @@ -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 + */ +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 index 00000000..b50feef1 --- /dev/null +++ b/src/net/sf/openrocket/util/FatalException.java @@ -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 + * @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); + } + +} diff --git a/src/net/sf/openrocket/util/LinearInterpolator.java b/src/net/sf/openrocket/util/LinearInterpolator.java index 00efe3a4..e94a3976 100644 --- a/src/net/sf/openrocket/util/LinearInterpolator.java +++ b/src/net/sf/openrocket/util/LinearInterpolator.java @@ -109,7 +109,7 @@ public class LinearInterpolator implements Cloneable { other.sortMap = (TreeMap)this.sortMap.clone(); return other; } catch (CloneNotSupportedException e) { - throw new RuntimeException("CloneNotSupportedException?!",e); + throw new BugException("CloneNotSupportedException?!",e); } } diff --git a/src/net/sf/openrocket/util/Pair.java b/src/net/sf/openrocket/util/Pair.java index e95587b5..9a562cb8 100644 --- a/src/net/sf/openrocket/util/Pair.java +++ b/src/net/sf/openrocket/util/Pair.java @@ -62,4 +62,10 @@ public class Pair { return ((u != null) ? u.hashCode() : 0) + ((v != null) ? v.hashCode() : 0); } + + @Override + public String toString() { + return "[" + u + ";" + v + "]"; + } + } diff --git a/src/net/sf/openrocket/util/Prefs.java b/src/net/sf/openrocket/util/Prefs.java index 70a3e558..eb2e3d47 100644 --- a/src/net/sf/openrocket/util/Prefs.java +++ b/src/net/sf/openrocket/util/Prefs.java @@ -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); diff --git a/src/net/sf/openrocket/util/Quaternion.java b/src/net/sf/openrocket/util/Quaternion.java index 3c457cab..ee2a2d25 100644 --- a/src/net/sf/openrocket/util/Quaternion.java +++ b/src/net/sf/openrocket/util/Quaternion.java @@ -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"); } } diff --git a/src/net/sf/openrocket/util/Reflection.java b/src/net/sf/openrocket/util/Reflection.java index 26c00bef..d837a497 100644 --- a/src/net/sf/openrocket/util/Reflection.java +++ b/src/net/sf/openrocket/util/Reflection.java @@ -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. + *

+ * This method has a return type of Error in order to allow writing code like: + *

throw Reflection.handleInvocationTargetException(e)
+ * 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"); } } diff --git a/src/net/sf/openrocket/util/SaveCSVWorker.java b/src/net/sf/openrocket/util/SaveCSVWorker.java index a4a65c46..aeb68ad4 100644 --- a/src/net/sf/openrocket/util/SaveCSVWorker.java +++ b/src/net/sf/openrocket/util/SaveCSVWorker.java @@ -118,11 +118,11 @@ public class SaveCSVWorker extends SwingWorker { 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; diff --git a/test/net/sf/openrocket/communication/HttpURLConnectionMock.java b/test/net/sf/openrocket/communication/HttpURLConnectionMock.java index 0ae317b3..ab5c48ab 100644 --- a/test/net/sf/openrocket/communication/HttpURLConnectionMock.java +++ b/test/net/sf/openrocket/communication/HttpURLConnectionMock.java @@ -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 index 00000000..217332be --- /dev/null +++ b/test/net/sf/openrocket/util/ReflectionTest.java @@ -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()); + } + + } + +}