diff --git a/.classpath b/.classpath
index 9df09db58..c71fbb9c8 100644
--- a/.classpath
+++ b/.classpath
@@ -11,7 +11,7 @@
 	</classpathentry>
 	<classpathentry kind="lib" path="lib-extra/RXTXcomm.jar"/>
 	<classpathentry kind="lib" path="lib-test/junit-4.7.jar"/>
-	<classpathentry kind="lib" path="lib/jfreechart-1.0.13.jar"/>
+	<classpathentry kind="lib" path="lib/jfreechart-1.0.13.jar" sourcepath="/home/sampo/Projects/lib/jfreechart-1.0.13/source"/>
 	<classpathentry kind="lib" path="lib/jcommon-1.0.16.jar">
 		<accessrules>
 			<accessrule kind="nonaccessible" pattern="org/jfree/util/Log"/>
diff --git a/ChangeLog b/ChangeLog
index 58bb84c16..f958fe54b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,15 @@
+2010-07-21  Sampo Niskanen
+
+	* Implemented enhanced motor selection dialog
+	* Background motor loading & startup time optimization
+
+2010-07-20  Doug Pedrick
+
+	* [BUG] Exception when loading Rocksim files
+
 2010-07-19  Sampo Niskanen
 
-	* Small bug fixes
+	* [BUG] Various small bug fixes
 
 2010-07-18  Sampo Niskanen
 
diff --git a/doc/properties.txt b/doc/properties.txt
index 202bc87ea..cf2982564 100644
--- a/doc/properties.txt
+++ b/doc/properties.txt
@@ -28,6 +28,9 @@ Debugging options
 openrocket.debug.menu
 	If defined the "Debug" menu will be displayed in the main application window.
 
+openrocket.debug.prefs
+	If defined a new, clean set of preferences will be used (does not overwrite the existing preferences).
+
 openrocket.debug.bugurl
 	URL used for sending bug reports.
 
diff --git a/run.sh b/run.sh
new file mode 100755
index 000000000..abf2f1c8c
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+#
+# This script runs the version of OpenRocket compiled by Eclipse from
+# the bin/ directory.  You can provide Java arguments and OpenRocket
+# arguments.
+#
+
+JAVAOPTS=""
+
+while echo "$1" | grep -q "^-" ; do
+    JAVAOPTS="$JAVAOPTS $1"
+    shift
+done
+
+
+java -cp bin/:lib/miglayout15-swing.jar:lib/jcommon-1.0.16.jar:lib/jfreechart-1.0.13.jar:. $JAVAOPTS net.sf.openrocket.startup.Startup "$@"
+
diff --git a/src/net/sf/openrocket/database/Databases.java b/src/net/sf/openrocket/database/Databases.java
index 6031f40b1..fe6abcbf2 100644
--- a/src/net/sf/openrocket/database/Databases.java
+++ b/src/net/sf/openrocket/database/Databases.java
@@ -1,20 +1,9 @@
 package net.sf.openrocket.database;
 
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-
-import net.sf.openrocket.file.GeneralMotorLoader;
-import net.sf.openrocket.file.Loader;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.material.MaterialStorage;
-import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.util.ConfigurationException;
-import net.sf.openrocket.util.JarUtil;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Prefs;
 
@@ -28,12 +17,7 @@ public class Databases {
 	private static final LogHelper log = Application.getLogger();
 	
 	/* Static implementations of specific databases: */
-	/**
-	 * The motor database.
-	 * TODO: HIGH:  Must cast to (Loader) to works, very ugly.  In practice returns only ThrustCurveMotors currently.
-	 */
-	public static final Database<ThrustCurveMotor> MOTOR = new Database<ThrustCurveMotor>((Loader) new GeneralMotorLoader());
-	
+
 	/**
 	 * A database of bulk materials (with bulk densities).
 	 */
@@ -49,34 +33,6 @@ public class Databases {
 	
 
 
-	// TODO: HIGH: loading the thrust curves and other databases
-	static {
-		final String filePattern = ".*\\.([eE][nN][gG]|[rR][sS][eE])$";
-		try {
-			MOTOR.loadJarDirectory("datafiles/thrustcurves/", filePattern);
-		} catch (Exception e) {
-			System.out.println("Could not read thrust curves from JAR: " + e.getMessage());
-			
-			// Try to find directory as a system resource
-			File dir;
-			URL url = ClassLoader.getSystemResource("datafiles/thrustcurves/");
-			
-			try {
-				dir = JarUtil.urlToFile(url);
-			} catch (Exception e1) {
-				dir = new File("datafiles/thrustcurves/");
-			}
-			
-			try {
-				MOTOR.loadDirectory(dir, filePattern);
-			} catch (IOException e1) {
-				System.out.println("Could not read thrust curves from directory either.");
-				throw new ConfigurationException("Couldn't read thrust curves from either " +
-						"JAR file or system resource directory", e1);
-			}
-		}
-	}
-	
 	static {
 		
 		// Add default materials
@@ -228,40 +184,5 @@ public class Databases {
 		return Material.newMaterial(type, name, density, userDefined);
 	}
 	
-	
 
-	/**
-	 * Return all motor in the database matching a search criteria.  Any search criteria that
-	 * is null or NaN is ignored.
-	 * 
-	 * @param type			the motor type, or null.
-	 * @param manufacturer	the manufacturer, or null.
-	 * @param designation	the designation, or null.
-	 * @param diameter		the diameter, or NaN.
-	 * @param length		the length, or NaN.
-	 * @return				an array of all the matching motors.
-	 */
-	public static Motor[] findMotors(Motor.Type type, String manufacturer, String designation, double diameter, double length) {
-		ArrayList<Motor> results = new ArrayList<Motor>();
-		
-		for (ThrustCurveMotor m : MOTOR) {
-			boolean match = true;
-			if (type != null && type != m.getMotorType())
-				match = false;
-			else if (manufacturer != null && !m.getManufacturer().matches(manufacturer))
-				match = false;
-			else if (designation != null && !designation.equalsIgnoreCase(m.getDesignation()))
-				match = false;
-			else if (!Double.isNaN(diameter) && (Math.abs(diameter - m.getDiameter()) > 0.0015))
-				match = false;
-			else if (!Double.isNaN(length) && (Math.abs(length - m.getLength()) > 0.0015))
-				match = false;
-			
-			if (match)
-				results.add(m);
-		}
-		
-		return results.toArray(new Motor[0]);
-	}
-	
 }
diff --git a/src/net/sf/openrocket/database/ThrustCurveMotorSet.java b/src/net/sf/openrocket/database/ThrustCurveMotorSet.java
index afffd30bb..dfd7cb55c 100644
--- a/src/net/sf/openrocket/database/ThrustCurveMotorSet.java
+++ b/src/net/sf/openrocket/database/ThrustCurveMotorSet.java
@@ -13,14 +13,14 @@ import java.util.regex.Pattern;
 
 import net.sf.openrocket.motor.DesignationComparator;
 import net.sf.openrocket.motor.Manufacturer;
-import net.sf.openrocket.motor.MotorDigest;
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.motor.MotorDigest;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.motor.Motor.Type;
 import net.sf.openrocket.util.MathUtil;
 
 public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
-
+	
 	//  Comparators:
 	private static final Collator COLLATOR = Collator.getInstance(Locale.US);
 	static {
@@ -28,12 +28,12 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	}
 	private static final DesignationComparator DESIGNATION_COMPARATOR = new DesignationComparator();
 	private static final ThrustCurveMotorComparator comparator = new ThrustCurveMotorComparator();
+	
+
 
-	
-	
 	private final ArrayList<ThrustCurveMotor> motors = new ArrayList<ThrustCurveMotor>();
 	private final Map<ThrustCurveMotor, String> digestMap =
-		new IdentityHashMap<ThrustCurveMotor, String>();
+			new IdentityHashMap<ThrustCurveMotor, String>();
 	
 	private final List<Double> delays = new ArrayList<Double>();
 	
@@ -45,7 +45,7 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	private Motor.Type type = Motor.Type.UNKNOWN;
 	
 	
-	
+
 	public void addMotor(ThrustCurveMotor motor) {
 		
 		// Check for first insertion
@@ -60,8 +60,8 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 		// Verify that the motor can be added
 		if (!matches(motor)) {
 			throw new IllegalArgumentException("Motor does not match the set:" +
-					" manufacturer="+manufacturer +
-					" designation="+designation +
+					" manufacturer=" + manufacturer +
+					" designation=" + designation +
 					" diameter=" + diameter +
 					" length=" + length +
 					" set_size=" + motors.size() +
@@ -71,6 +71,12 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 		// Update the type if now known
 		if (type == Motor.Type.UNKNOWN) {
 			type = motor.getMotorType();
+			// Add "Plugged" option if hybrid
+			if (type == Motor.Type.HYBRID) {
+				if (!delays.contains(Motor.PLUGGED)) {
+					delays.add(Motor.PLUGGED);
+				}
+			}
 		}
 		
 		// Change the simplified designation if necessary
@@ -79,23 +85,25 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 		}
 		
 		// Add the standard delays
-		for (double d: motor.getStandardDelays()) {
+		for (double d : motor.getStandardDelays()) {
 			d = Math.rint(d);
-			delays.add(d);
+			if (!delays.contains(d)) {
+				delays.add(d);
+			}
 		}
 		Collections.sort(delays);
 		
-		
+
 		// Check whether to add as new motor or overwrite existing
 		final String digest = MotorDigest.digestMotor(motor);
 		for (int index = 0; index < motors.size(); index++) {
 			Motor m = motors.get(index);
-
+			
 			if (digest.equals(digestMap.get(m)) &&
 					motor.getDesignation().equals(m.getDesignation())) {
-
+				
 				// Match found, check which one to keep (or both) based on comment
-				String newCmt = motor.getDescription().replaceAll("\\s+"," ").trim();
+				String newCmt = motor.getDescription().replaceAll("\\s+", " ").trim();
 				String oldCmt = m.getDescription().replaceAll("\\s+", " ").trim();
 				
 				if (newCmt.length() == 0 || newCmt.equals(oldCmt)) {
@@ -123,7 +131,7 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public boolean matches(ThrustCurveMotor m) {
 		if (motors.isEmpty())
 			return true;
-
+		
 		if (manufacturer != m.getManufacturer())
 			return false;
 		
@@ -133,7 +141,7 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 		if (!MathUtil.equals(length, m.getLength()))
 			return false;
 		
-		if ((type != Type.UNKNOWN) && (m.getMotorType()!= Type.UNKNOWN) && 
+		if ((type != Type.UNKNOWN) && (m.getMotorType() != Type.UNKNOWN) &&
 				(type != m.getMotorType())) {
 			return false;
 		}
@@ -143,7 +151,7 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 		
 		return true;
 	}
-
+	
 	
 	@SuppressWarnings("unchecked")
 	public List<ThrustCurveMotor> getMotors() {
@@ -151,6 +159,10 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	}
 	
 	
+	public int getMotorCount() {
+		return motors.size();
+	}
+	
 	
 	/**
 	 * Return the standard delays applicable to this motor type.  This is a union of
@@ -160,8 +172,8 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public List<Double> getDelays() {
 		return Collections.unmodifiableList(delays);
 	}
-
-
+	
+	
 	/**
 	 * Return the manufacturer of this motor type.
 	 * @return the manufacturer
@@ -169,8 +181,8 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public Manufacturer getManufacturer() {
 		return manufacturer;
 	}
-
-
+	
+	
 	/**
 	 * Return the designation of this motor type.  This is either the exact or simplified
 	 * designation, depending on what motors have been added.
@@ -179,8 +191,8 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public String getDesignation() {
 		return designation;
 	}
-
-
+	
+	
 	/**
 	 * Return the diameter of this motor type.
 	 * @return the diameter
@@ -188,8 +200,8 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public double getDiameter() {
 		return diameter;
 	}
-
-
+	
+	
 	/**
 	 * Return the length of this motor type.
 	 * @return the length
@@ -197,8 +209,8 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public double getLength() {
 		return length;
 	}
-
-
+	
+	
 	/**
 	 * Return the type of this motor type.  If any of the added motors has a type different
 	 * from UNKNOWN, then that type will be returned.
@@ -207,12 +219,21 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	public Motor.Type getType() {
 		return type;
 	}
+	
+	
 
 
-
+	@Override
+	public String toString() {
+		return "ThrustCurveMotorSet[" + manufacturer + " " + designation +
+				", type=" + type + ", count=" + motors.size() + "]";
+	}
+	
+	
 
 
 	private static final Pattern SIMPLIFY_PATTERN = Pattern.compile("^[0-9]*[ -]*([A-Z][0-9]+).*");
+	
 	/**
 	 * Simplify a motor designation, if possible.  This attempts to reduce the designation
 	 * into a simple letter + number notation for the impulse class and average thrust.
@@ -235,7 +256,7 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 	 * Comparator for deciding in which order to display matching motors.
 	 */
 	private static class ThrustCurveMotorComparator implements Comparator<ThrustCurveMotor> {
-
+		
 		@Override
 		public int compare(ThrustCurveMotor o1, ThrustCurveMotor o2) {
 			// 1. Designation
@@ -253,15 +274,15 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 		}
 		
 	}
-
-
+	
+	
 	@Override
 	public int compareTo(ThrustCurveMotorSet other) {
-
+		
 		int value;
 		
 		// 1. Manufacturer
-		value = COLLATOR.compare(this.manufacturer.getDisplayName(), 
+		value = COLLATOR.compare(this.manufacturer.getDisplayName(),
 				other.manufacturer.getDisplayName());
 		if (value != 0)
 			return value;
@@ -272,12 +293,12 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
 			return value;
 		
 		// 3. Diameter
-		value = (int)((this.diameter - other.diameter)*1000000);
+		value = (int) ((this.diameter - other.diameter) * 1000000);
 		if (value != 0)
 			return value;
-				
+		
 		// 4. Length
-		value = (int)((this.length - other.length)*1000000);
+		value = (int) ((this.length - other.length) * 1000000);
 		return value;
 		
 	}
diff --git a/src/net/sf/openrocket/database/MotorSetDatabase.java b/src/net/sf/openrocket/database/ThrustCurveMotorSetDatabase.java
similarity index 65%
rename from src/net/sf/openrocket/database/MotorSetDatabase.java
rename to src/net/sf/openrocket/database/ThrustCurveMotorSetDatabase.java
index 4cd48f500..d1511595d 100644
--- a/src/net/sf/openrocket/database/MotorSetDatabase.java
+++ b/src/net/sf/openrocket/database/ThrustCurveMotorSetDatabase.java
@@ -5,6 +5,7 @@ import java.util.Collections;
 import java.util.List;
 
 import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.startup.Application;
 
@@ -14,27 +15,29 @@ import net.sf.openrocket.startup.Application;
  * 
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
-public abstract class MotorSetDatabase {
+public abstract class ThrustCurveMotorSetDatabase {
 	
 	private static final LogHelper logger = Application.getLogger();
-
-	private List<ThrustCurveMotorSet> motorSets;
+	
+	protected List<ThrustCurveMotorSet> motorSets;
 	
 	private volatile boolean startedLoading = false;
 	private volatile boolean endedLoading = false;
 	private final boolean asynchronous;
 	
+	/** Set to true the first time {@link #blockUntilLoaded()} is called. */
+	protected volatile boolean inUse = false;
 	
 	/**
 	 * Sole constructor.
 	 * 
 	 * @param asynchronous	whether to load motors asynchronously in a background thread.
 	 */
-	public MotorSetDatabase(boolean asynchronous) {
+	public ThrustCurveMotorSetDatabase(boolean asynchronous) {
 		this.asynchronous = asynchronous;
 	}
 	
-
+	
 	/**
 	 * Return a list of the ThrustCurveMotorSet objects.  The list is in sorted order and
 	 * is unmodifiable.
@@ -46,9 +49,46 @@ public abstract class MotorSetDatabase {
 		return motorSets;
 	}
 	
-
 	
 
+	/**
+	 * Return all motors in the database matching a search criteria.  Any search criteria that
+	 * is null or NaN is ignored.
+	 * 
+	 * @param type			the motor type, or null.
+	 * @param manufacturer	the manufacturer, or null.
+	 * @param designation	the designation, or null.
+	 * @param diameter		the diameter, or NaN.
+	 * @param length		the length, or NaN.
+	 * @return				a list of all the matching motors.
+	 */
+	public List<ThrustCurveMotor> findMotors(Motor.Type type, String manufacturer, String designation,
+			double diameter, double length) {
+		blockUntilLoaded();
+		ArrayList<ThrustCurveMotor> results = new ArrayList<ThrustCurveMotor>();
+		
+		for (ThrustCurveMotorSet set : motorSets) {
+			for (ThrustCurveMotor m : set.getMotors()) {
+				boolean match = true;
+				if (type != null && type != set.getType())
+					match = false;
+				else if (manufacturer != null && !m.getManufacturer().matches(manufacturer))
+					match = false;
+				else if (designation != null && !designation.equalsIgnoreCase(m.getDesignation()))
+					match = false;
+				else if (!Double.isNaN(diameter) && (Math.abs(diameter - m.getDiameter()) > 0.0015))
+					match = false;
+				else if (!Double.isNaN(length) && (Math.abs(length - m.getLength()) > 0.0015))
+					match = false;
+				
+				if (match)
+					results.add(m);
+			}
+		}
+		
+		return results;
+	}
+	
 	
 	/**
 	 * Add a motor to the database.  If a matching ThrustCurveMototSet is found, 
@@ -59,7 +99,7 @@ public abstract class MotorSetDatabase {
 	 */
 	protected void addMotor(ThrustCurveMotor motor) {
 		// Iterate from last to first, as this is most likely to hit early when loading files
-		for (int i = motorSets.size()-1; i>= 0; i--) {
+		for (int i = motorSets.size() - 1; i >= 0; i--) {
 			ThrustCurveMotorSet set = motorSets.get(i);
 			if (set.matches(motor)) {
 				set.addMotor(motor);
@@ -73,9 +113,9 @@ public abstract class MotorSetDatabase {
 	}
 	
 	
-	
-	
-	
+
+
+
 	/**
 	 * Start loading the motors.  If asynchronous 
 	 * 
@@ -102,7 +142,17 @@ public abstract class MotorSetDatabase {
 	public boolean isLoaded() {
 		return endedLoading;
 	}
-
+	
+	
+	/**
+	 * Mark that this database is in use or a place is waiting for the database to 
+	 * become loaded.  This can be used in conjunction with {@link #isLoaded()} to load
+	 * the database without blocking.
+	 */
+	public void setInUse() {
+		inUse = true;
+	}
+	
 	
 	/**
 	 * Block the current thread until loading of the motors has been completed.
@@ -110,6 +160,7 @@ public abstract class MotorSetDatabase {
 	 * @throws IllegalStateException	if startLoading() has not been called.
 	 */
 	public void blockUntilLoaded() {
+		inUse = true;
 		if (!startedLoading) {
 			throw new IllegalStateException("startLoading() has not been called");
 		}
@@ -125,7 +176,7 @@ public abstract class MotorSetDatabase {
 			}
 		}
 	}
-
+	
 	
 	/**
 	 * Used for loading the motor database.  This method will be called in a background
@@ -135,7 +186,7 @@ public abstract class MotorSetDatabase {
 	protected abstract void loadMotors();
 	
 	
-	
+
 	/**
 	 * Creates the motor list, calls {@link #loadMotors()}, sorts the list and marks
 	 * the motors as loaded.  This method is called either synchronously or from the
@@ -150,9 +201,9 @@ public abstract class MotorSetDatabase {
 		}
 		Collections.sort(motorSets);
 		motorSets = Collections.unmodifiableList(motorSets);
-		synchronized (MotorSetDatabase.this) {
+		synchronized (ThrustCurveMotorSetDatabase.this) {
 			endedLoading = true;
-			MotorSetDatabase.this.notifyAll();
+			ThrustCurveMotorSetDatabase.this.notifyAll();
 		}
 	}
 	
@@ -168,5 +219,5 @@ public abstract class MotorSetDatabase {
 			performMotorLoading();
 		}
 	}
-
+	
 }
diff --git a/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java b/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java
index d9b57a833..db0ca84e5 100644
--- a/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java
+++ b/src/net/sf/openrocket/file/openrocket/OpenRocketLoader.java
@@ -23,6 +23,7 @@ import net.sf.openrocket.file.simplesax.PlainTextHandler;
 import net.sf.openrocket.file.simplesax.SimpleSAX;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.rocketcomponent.BodyComponent;
 import net.sf.openrocket.rocketcomponent.BodyTube;
 import net.sf.openrocket.rocketcomponent.Bulkhead;
@@ -67,6 +68,7 @@ import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.GUISimulationConditions;
 import net.sf.openrocket.simulation.FlightEvent.Type;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
@@ -988,21 +990,22 @@ class MotorHandler extends ElementHandler {
 			warnings.add(Warning.fromString("No motor specified, ignoring."));
 			return null;
 		}
-		Motor[] motors = Databases.findMotors(type, manufacturer, designation, diameter, length);
-		if (motors.length == 0) {
+		List<ThrustCurveMotor> motors = Application.getMotorSetDatabase().findMotors(type, manufacturer,
+				designation, diameter, length);
+		if (motors.size() == 0) {
 			String str = "No motor with designation '" + designation + "'";
 			if (manufacturer != null)
 				str += " for manufacturer '" + manufacturer + "'";
 			warnings.add(Warning.fromString(str + " found."));
 			return null;
 		}
-		if (motors.length > 1) {
+		if (motors.size() > 1) {
 			String str = "Multiple motors with designation '" + designation + "'";
 			if (manufacturer != null)
 				str += " for manufacturer '" + manufacturer + "'";
 			warnings.add(Warning.fromString(str + " found, one chosen arbitrarily."));
 		}
-		return motors[0];
+		return motors.get(0);
 	}
 	
 	
diff --git a/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java b/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
index b2ddc16f1..e37d80ee9 100644
--- a/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
+++ b/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
@@ -32,42 +32,43 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 	private static final String CONFIGDIALOGPACKAGE = "net.sf.openrocket.gui.configdialog";
 	private static final String CONFIGDIALOGPOSTFIX = "Config";
 	
-	
-	private static ComponentConfigDialog dialog = null;
 
+	private static ComponentConfigDialog dialog = null;
 	
+
 	private OpenRocketDocument document = null;
 	private RocketComponent component = null;
 	private RocketComponentConfig configurator = null;
 	
 	private final Window parent;
 	
-	private ComponentConfigDialog(Window parent, OpenRocketDocument document, 
+	private ComponentConfigDialog(Window parent, OpenRocketDocument document,
 			RocketComponent component) {
 		super(parent);
 		this.parent = parent;
 		
 		setComponent(document, component);
 		
+		GUIUtil.setDisposableDialogOptions(this, null);
+		
 		// Set window position according to preferences, and set prefs when moving
 		Point position = Prefs.getWindowPosition(this.getClass());
-		if (position == null)
-			this.setLocationByPlatform(true);
-		else
+		if (position != null) {
+			this.setLocationByPlatform(false);
 			this.setLocation(position);
-
+		}
+		
 		this.addComponentListener(new ComponentAdapter() {
 			@Override
 			public void componentMoved(ComponentEvent e) {
-				Prefs.setWindowPosition(ComponentConfigDialog.this.getClass(), 
+				Prefs.setWindowPosition(ComponentConfigDialog.this.getClass(),
 						ComponentConfigDialog.this.getLocation());
 			}
 		});
 		
-		GUIUtil.setDisposableDialogOptions(this, null);
 	}
 	
-
+	
 	/**
 	 * Set the component being configured.  The listening connections of the old configurator
 	 * will be removed and the new ones created.
@@ -78,10 +79,10 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 		if (this.document != null) {
 			this.document.getRocket().removeComponentChangeListener(this);
 		}
-
+		
 		if (configurator != null) {
 			// Remove listeners by setting all applicable models to null
-			GUIUtil.setNullModels(configurator);  // null-safe
+			GUIUtil.setNullModels(configurator); // null-safe
 		}
 		
 		this.document = document;
@@ -92,11 +93,11 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 		this.setContentPane(configurator);
 		configurator.updateFields();
 		
-		setTitle(component.getComponentName()+" configuration");
-
-//		Dimension pref = getPreferredSize();
-//		Dimension real = getSize();
-//		if (pref.width > real.width || pref.height > real.height)
+		setTitle(component.getComponentName() + " configuration");
+		
+		//		Dimension pref = getPreferredSize();
+		//		Dimension real = getSize();
+		//		if (pref.width > real.width || pref.height > real.height)
 		this.pack();
 	}
 	
@@ -104,15 +105,15 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 	 * Return the configurator panel of the current component.
 	 */
 	private RocketComponentConfig getDialogContents() {
-		Constructor<? extends RocketComponentConfig> c = 
-			findDialogContentsConstructor(component);
+		Constructor<? extends RocketComponentConfig> c =
+				findDialogContentsConstructor(component);
 		if (c != null) {
 			try {
 				return (RocketComponentConfig) c.newInstance(component);
 			} catch (InstantiationException e) {
-				throw new BugException("BUG in constructor reflection",e);
+				throw new BugException("BUG in constructor reflection", e);
 			} catch (IllegalAccessException e) {
-				throw new BugException("BUG in constructor reflection",e);
+				throw new BugException("BUG in constructor reflection", e);
 			} catch (InvocationTargetException e) {
 				throw Reflection.handleWrappedException(e);
 			}
@@ -120,16 +121,15 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 		
 		// Should never be reached, since RocketComponentConfig should catch all
 		// components without their own configurator.
-		throw new BugException("Unable to find any configurator for "+component);
+		throw new BugException("Unable to find any configurator for " + component);
 	}
-
+	
 	/**
 	 * Finds the Constructor of the given component's config dialog panel in 
 	 * CONFIGDIALOGPACKAGE.
 	 */
 	@SuppressWarnings("unchecked")
-	private static Constructor<? extends RocketComponentConfig> 
-			findDialogContentsConstructor(RocketComponent component) {
+	private static Constructor<? extends RocketComponentConfig> findDialogContentsConstructor(RocketComponent component) {
 		Class<?> currentclass;
 		String currentclassname;
 		String configclassname;
@@ -143,23 +143,24 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 			int index = currentclassname.lastIndexOf('.');
 			if (index >= 0)
 				currentclassname = currentclassname.substring(index + 1);
-			configclassname = CONFIGDIALOGPACKAGE + "." + currentclassname + 
-				CONFIGDIALOGPOSTFIX;
+			configclassname = CONFIGDIALOGPACKAGE + "." + currentclassname +
+					CONFIGDIALOGPOSTFIX;
 			
 			try {
 				configclass = Class.forName(configclassname);
 				c = (Constructor<? extends RocketComponentConfig>)
-					configclass.getConstructor(RocketComponent.class);
+						configclass.getConstructor(RocketComponent.class);
 				return c;
-			} catch (Exception ignore) { }
-
+			} catch (Exception ignore) {
+			}
+			
 			currentclass = currentclass.getSuperclass();
 		}
 		return null;
 	}
 	
 	
-	
+
 
 	//////////  Static dialog  /////////
 	
@@ -170,7 +171,7 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 	 * @param document		the document to configure.
 	 * @param component		the component to configure.
 	 */
-	public static void showDialog(Window parent, OpenRocketDocument document, 
+	public static void showDialog(Window parent, OpenRocketDocument document,
 			RocketComponent component) {
 		if (dialog != null)
 			dialog.dispose();
@@ -178,11 +179,11 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 		dialog = new ComponentConfigDialog(parent, document, component);
 		dialog.setVisible(true);
 		
-		document.addUndoPosition("Modify "+component.getComponentName());
+		document.addUndoPosition("Modify " + component.getComponentName());
 	}
 	
 	
-	/* package */ 
+	/* package */
 	static void showDialog(RocketComponent component) {
 		showDialog(dialog.parent, dialog.document, component);
 	}
@@ -194,7 +195,7 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 		if (dialog != null)
 			dialog.setVisible(false);
 	}
-
+	
 	
 	/**
 	 * Add an undo position for the current document.  This is intended for use only
@@ -202,7 +203,7 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 	 * 
 	 * @param description  Description of the undoable action
 	 */
-	/*package*/ static void addUndoPosition(String description) {
+	/*package*/static void addUndoPosition(String description) {
 		if (dialog == null) {
 			throw new IllegalStateException("Dialog not open, report bug!");
 		}
@@ -221,16 +222,16 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 	 * Returns whether the singleton configuration dialog is currently visible or not.
 	 */
 	public static boolean isDialogVisible() {
-		return (dialog!=null) && (dialog.isVisible());
+		return (dialog != null) && (dialog.isVisible());
 	}
-
-
+	
+	
 	public void componentChanged(ComponentChangeEvent e) {
 		if (e.isTreeChange() || e.isUndoChange()) {
 			
 			// Hide dialog in case of tree or undo change
 			dialog.setVisible(false);
-
+			
 		} else {
 			/*
 			 * TODO: HIGH:  The line below has caused a NullPointerException (without null check)
diff --git a/src/net/sf/openrocket/gui/configdialog/MotorConfig.java b/src/net/sf/openrocket/gui/configdialog/MotorConfig.java
index 1e93a6085..45a134a2b 100644
--- a/src/net/sf/openrocket/gui/configdialog/MotorConfig.java
+++ b/src/net/sf/openrocket/gui/configdialog/MotorConfig.java
@@ -13,6 +13,7 @@ import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JSpinner;
+import javax.swing.SwingUtilities;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
@@ -25,7 +26,7 @@ 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.gui.dialogs.motor.MotorChooserDialog;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.rocketcomponent.Configuration;
@@ -150,9 +151,9 @@ public class MotorConfig extends JPanel {
 			public void actionPerformed(ActionEvent e) {
 				String id = configuration.getMotorConfigurationID();
 				
-				// TODO: HIGH: Assumes only ThrustCurveMotors exist
-				MotorChooserDialog dialog = new MotorChooserDialog((ThrustCurveMotor) mount.getMotor(id),
-						mount.getMotorDelay(id), mount.getMotorMountDiameter());
+				MotorChooserDialog dialog = new MotorChooserDialog(mount.getMotor(id),
+						mount.getMotorDelay(id), mount.getMotorMountDiameter(),
+						SwingUtilities.getWindowAncestor(MotorConfig.this));
 				dialog.setVisible(true);
 				Motor m = dialog.getSelectedMotor();
 				double d = dialog.getSelectedDelay();
@@ -204,7 +205,7 @@ public class MotorConfig extends JPanel {
 		} else {
 			String str = "";
 			if (m instanceof ThrustCurveMotor)
-				str = ((ThrustCurveMotor) m).getManufacturer() + "";
+				str = ((ThrustCurveMotor) m).getManufacturer() + " ";
 			str += m.getDesignation(mount.getMotorDelay(id));
 			motorLabel.setText(str);
 		}
diff --git a/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java b/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java
index 3fa7db8c0..a4390cf46 100644
--- a/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java
+++ b/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java
@@ -26,9 +26,9 @@ import javax.swing.table.TableColumnModel;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.dialogs.motor.MotorChooserDialog;
 import net.sf.openrocket.gui.main.BasicFrame;
 import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
@@ -317,10 +317,8 @@ public class EditMotorConfigurationDialog extends JDialog {
 		if (currentID == null || currentMount == null)
 			return;
 		
-		// TODO: HIGH: Assumes only ThrustCurveMotors exist
-		MotorChooserDialog dialog = new MotorChooserDialog((ThrustCurveMotor) currentMount.getMotor(currentID),
-				currentMount.getMotorDelay(currentID), currentMount.getMotorMountDiameter(),
-				this);
+		MotorChooserDialog dialog = new MotorChooserDialog(currentMount.getMotor(currentID),
+				currentMount.getMotorDelay(currentID), currentMount.getMotorMountDiameter(), this);
 		dialog.setVisible(true);
 		Motor m = dialog.getSelectedMotor();
 		double d = dialog.getSelectedDelay();
diff --git a/src/net/sf/openrocket/gui/dialogs/MotorChooserDialog.java b/src/net/sf/openrocket/gui/dialogs/MotorChooserDialog.java
deleted file mode 100644
index 4e4db29fb..000000000
--- a/src/net/sf/openrocket/gui/dialogs/MotorChooserDialog.java
+++ /dev/null
@@ -1,665 +0,0 @@
-package net.sf.openrocket.gui.dialogs;
-
-
-import java.awt.Dialog;
-import java.awt.Font;
-import java.awt.Rectangle;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Comparator;
-
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.RowFilter;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.TableModel;
-import javax.swing.table.TableRowSorter;
-
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.database.Databases;
-import net.sf.openrocket.gui.components.StyledLabel;
-import net.sf.openrocket.motor.DesignationComparator;
-import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.motor.ThrustCurveMotor;
-import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.unit.Value;
-import net.sf.openrocket.unit.ValueComparator;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.Prefs;
-
-/*
- * TODO: HIGH: Only supports ThrustCurveMotors
- */
-public class MotorChooserDialog extends JDialog {
-	
-	private static final int SHOW_ALL = 0;
-	private static final int SHOW_SMALLER = 1;
-	private static final int SHOW_EXACT = 2;
-	private static final String[] SHOW_DESCRIPTIONS = {
-			"Show all motors",
-			"Show motors with diameter less than that of the motor mount",
-			"Show motors with diameter equal to that of the motor mount"
-	};
-	private static final int SHOW_MAX = 2;
-	
-	private final JTextField searchField;
-	private String[] searchTerms = new String[0];
-	
-	private final double diameter;
-	
-	private ThrustCurveMotor selectedMotor = null;
-	private double selectedDelay = 0;
-	
-	private JTable table;
-	private TableRowSorter<TableModel> sorter;
-	private JComboBox delayBox;
-	private MotorDatabaseModel model;
-	
-	private boolean okClicked = false;
-	
-	
-	public MotorChooserDialog(double diameter) {
-		this(null, 5, diameter, null);
-	}
-	
-	public MotorChooserDialog(ThrustCurveMotor current, double delay, double diameter) {
-		this(current, delay, diameter, null);
-	}
-	
-	public MotorChooserDialog(ThrustCurveMotor current, double delay, double diameter, Window owner) {
-		super(owner, "Select a rocket motor", Dialog.ModalityType.APPLICATION_MODAL);
-		
-		JButton button;
-		
-		this.selectedMotor = current;
-		this.selectedDelay = delay;
-		this.diameter = diameter;
-		
-		JPanel panel = new JPanel(new MigLayout("fill", "[grow][]"));
-		
-		// Label
-		JLabel label = new JLabel("Select a rocket motor:");
-		label.setFont(label.getFont().deriveFont(Font.BOLD));
-		panel.add(label, "growx");
-		
-		label = new JLabel("Motor mount diameter: " +
-				UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(diameter));
-		panel.add(label, "gapleft para, wrap paragraph");
-		
-
-		// Diameter selection
-		JComboBox combo = new JComboBox(SHOW_DESCRIPTIONS);
-		combo.addActionListener(new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				JComboBox cb = (JComboBox) e.getSource();
-				int sel = cb.getSelectedIndex();
-				if ((sel < 0) || (sel > SHOW_MAX))
-					sel = SHOW_ALL;
-				switch (sel) {
-				case SHOW_ALL:
-					sorter.setRowFilter(new MotorRowFilterAll());
-					break;
-				
-				case SHOW_SMALLER:
-					sorter.setRowFilter(new MotorRowFilterSmaller());
-					break;
-				
-				case SHOW_EXACT:
-					sorter.setRowFilter(new MotorRowFilterExact());
-					break;
-				
-				default:
-					assert (false) : "Should not occur.";
-				}
-				Prefs.putChoise("MotorDiameterMatch", sel);
-				setSelectionVisible();
-			}
-		});
-		panel.add(combo, "growx 1000");
-		
-
-
-		label = new JLabel("Search:");
-		panel.add(label, "gapleft para, split 2");
-		
-		searchField = new JTextField();
-		searchField.getDocument().addDocumentListener(new DocumentListener() {
-			@Override
-			public void changedUpdate(DocumentEvent e) {
-				update();
-			}
-			
-			@Override
-			public void insertUpdate(DocumentEvent e) {
-				update();
-			}
-			
-			@Override
-			public void removeUpdate(DocumentEvent e) {
-				update();
-			}
-			
-			private void update() {
-				String text = searchField.getText().trim();
-				String[] split = text.split("\\s+");
-				ArrayList<String> list = new ArrayList<String>();
-				for (String s : split) {
-					s = s.trim().toLowerCase();
-					if (s.length() > 0) {
-						list.add(s);
-					}
-				}
-				searchTerms = list.toArray(new String[0]);
-				sorter.sort();
-			}
-		});
-		panel.add(searchField, "growx 1, wrap");
-		
-
-
-		// Table, overridden to show meaningful tooltip texts
-		model = new MotorDatabaseModel(current);
-		table = new JTable(model) {
-			@Override
-			public String getToolTipText(MouseEvent e) {
-				java.awt.Point p = e.getPoint();
-				int colIndex = columnAtPoint(p);
-				int viewRow = rowAtPoint(p);
-				if (viewRow < 0)
-					return null;
-				int rowIndex = convertRowIndexToModel(viewRow);
-				ThrustCurveMotor motor = model.getMotor(rowIndex);
-				
-				if (colIndex < 0 || colIndex >= MotorColumns.values().length)
-					return null;
-				
-				return MotorColumns.values()[colIndex].getToolTipText(motor);
-			}
-		};
-		
-		// Set comparators and widths
-		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		sorter = new TableRowSorter<TableModel>(model);
-		for (int i = 0; i < MotorColumns.values().length; i++) {
-			MotorColumns column = MotorColumns.values()[i];
-			sorter.setComparator(i, column.getComparator());
-			table.getColumnModel().getColumn(i).setPreferredWidth(column.getWidth());
-		}
-		table.setRowSorter(sorter);
-		
-		// Set selection and double-click listeners
-		table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-			@Override
-			public void valueChanged(ListSelectionEvent e) {
-				int row = table.getSelectedRow();
-				if (row >= 0) {
-					row = table.convertRowIndexToModel(row);
-					ThrustCurveMotor m = model.getMotor(row);
-					// TODO: HIGH: equals or == ?
-					if (!m.equals(selectedMotor)) {
-						selectedMotor = model.getMotor(row);
-						setDelays(true); // Reset delay times
-					}
-				}
-			}
-		});
-		table.addMouseListener(new MouseAdapter() {
-			@Override
-			public void mouseClicked(MouseEvent e) {
-				if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
-					okClicked = true;
-					MotorChooserDialog.this.setVisible(false);
-				}
-			}
-		});
-		// (Current selection and scrolling performed later)
-		
-		JScrollPane scrollpane = new JScrollPane();
-		scrollpane.setViewportView(table);
-		panel.add(scrollpane, "spanx, grow, width :700:, height :300:, wrap paragraph");
-		
-
-		// Ejection delay
-		panel.add(new JLabel("Select ejection charge delay:"), "spanx, split 3, gap rel");
-		
-		delayBox = new JComboBox();
-		delayBox.setEditable(true);
-		delayBox.addActionListener(new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				JComboBox cb = (JComboBox) e.getSource();
-				String sel = (String) cb.getSelectedItem();
-				if (sel.equalsIgnoreCase("None")) {
-					selectedDelay = Motor.PLUGGED;
-				} else {
-					try {
-						selectedDelay = Double.parseDouble(sel);
-					} catch (NumberFormatException ignore) {
-					}
-				}
-				setDelays(false);
-			}
-		});
-		panel.add(delayBox, "gapright unrel");
-		panel.add(new StyledLabel("(Number of seconds or \"None\")", -1), "wrap para");
-		setDelays(false);
-		
-
-		JButton okButton = new JButton("OK");
-		okButton.addActionListener(new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				okClicked = true;
-				MotorChooserDialog.this.setVisible(false);
-			}
-		});
-		panel.add(okButton, "spanx, split, tag ok");
-		
-		button = new JButton("Cancel");
-		button.addActionListener(new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				MotorChooserDialog.this.setVisible(false);
-			}
-		});
-		panel.add(button, "tag cancel");
-		
-
-		// Sets the filter:
-		int showMode = Prefs.getChoise("MotorDiameterMatch", SHOW_MAX, SHOW_EXACT);
-		combo.setSelectedIndex(showMode);
-		
-
-		this.add(panel);
-		this.pack();
-		//		this.setAlwaysOnTop(true);
-		
-		this.setLocationByPlatform(true);
-		GUIUtil.setDisposableDialogOptions(this, okButton);
-		
-		// Table can be scrolled only after pack() has been called
-		setSelectionVisible();
-		
-		// Focus the search field
-		searchField.grabFocus();
-	}
-	
-	private void setSelectionVisible() {
-		if (selectedMotor != null) {
-			int index = table.convertRowIndexToView(model.getIndex(selectedMotor));
-			table.getSelectionModel().setSelectionInterval(index, index);
-			Rectangle rect = table.getCellRect(index, 0, true);
-			rect = new Rectangle(rect.x, rect.y - 100, rect.width, rect.height + 200);
-			table.scrollRectToVisible(rect);
-		}
-	}
-	
-	
-	/**
-	 * Set the values in the delay combo box.  If <code>reset</code> is <code>true</code>
-	 * then sets the selected value as the value closest to selectedDelay, otherwise
-	 * leaves selection alone.
-	 */
-	private void setDelays(boolean reset) {
-		if (selectedMotor == null) {
-			
-			delayBox.setModel(new DefaultComboBoxModel(new String[] { "None" }));
-			delayBox.setSelectedIndex(0);
-			
-		} else {
-			
-			double[] delays = selectedMotor.getStandardDelays();
-			String[] delayStrings = new String[delays.length];
-			double currentDelay = selectedDelay; // Store current setting locally
-			
-			for (int i = 0; i < delays.length; i++) {
-				delayStrings[i] = ThrustCurveMotor.getDelayString(delays[i], "None");
-			}
-			delayBox.setModel(new DefaultComboBoxModel(delayStrings));
-			
-			if (reset) {
-				
-				// Find and set the closest value
-				double closest = Double.NaN;
-				for (int i = 0; i < delays.length; i++) {
-					// if-condition to always become true for NaN
-					if (!(Math.abs(delays[i] - currentDelay) > Math.abs(closest - currentDelay))) {
-						closest = delays[i];
-					}
-				}
-				if (!Double.isNaN(closest)) {
-					selectedDelay = closest;
-					delayBox.setSelectedItem(ThrustCurveMotor.getDelayString(closest, "None"));
-				} else {
-					delayBox.setSelectedItem("None");
-				}
-				
-			} else {
-				
-				selectedDelay = currentDelay;
-				delayBox.setSelectedItem(ThrustCurveMotor.getDelayString(currentDelay, "None"));
-				
-			}
-			
-		}
-	}
-	
-	
-
-	public ThrustCurveMotor getSelectedMotor() {
-		if (!okClicked)
-			return null;
-		return selectedMotor;
-	}
-	
-	
-	public double getSelectedDelay() {
-		return selectedDelay;
-	}
-	
-	
-
-
-	////////////////  JTable elements  ////////////////
-	
-
-	/**
-	 * Enum defining the table columns.
-	 */
-	private enum MotorColumns {
-		MANUFACTURER("Manufacturer", 100) {
-			@Override
-			public String getValue(ThrustCurveMotor m) {
-				return m.getManufacturer().getDisplayName();
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return Collator.getInstance();
-			}
-		},
-		DESIGNATION("Designation") {
-			@Override
-			public String getValue(ThrustCurveMotor m) {
-				return m.getDesignation();
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return new DesignationComparator();
-			}
-		},
-		TYPE("Type") {
-			@Override
-			public String getValue(ThrustCurveMotor m) {
-				return m.getMotorType().getName();
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return Collator.getInstance();
-			}
-		},
-		DIAMETER("Diameter") {
-			@Override
-			public Object getValue(ThrustCurveMotor m) {
-				return new Value(m.getDiameter(), UnitGroup.UNITS_MOTOR_DIMENSIONS);
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return ValueComparator.INSTANCE;
-			}
-		},
-		LENGTH("Length") {
-			@Override
-			public Object getValue(ThrustCurveMotor m) {
-				return new Value(m.getLength(), UnitGroup.UNITS_MOTOR_DIMENSIONS);
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return ValueComparator.INSTANCE;
-			}
-		},
-		IMPULSE("Impulse") {
-			@Override
-			public Object getValue(ThrustCurveMotor m) {
-				return new Value(m.getTotalImpulseEstimate(), UnitGroup.UNITS_IMPULSE);
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return ValueComparator.INSTANCE;
-			}
-		},
-		TIME("Burn time") {
-			@Override
-			public Object getValue(ThrustCurveMotor m) {
-				return new Value(m.getBurnTimeEstimate(), UnitGroup.UNITS_SHORT_TIME);
-			}
-			
-			@Override
-			public Comparator<?> getComparator() {
-				return ValueComparator.INSTANCE;
-			}
-		};
-		
-
-		private final String title;
-		private final int width;
-		
-		MotorColumns(String title) {
-			this(title, 50);
-		}
-		
-		MotorColumns(String title, int width) {
-			this.title = title;
-			this.width = width;
-		}
-		
-		
-		public abstract Object getValue(ThrustCurveMotor m);
-		
-		public abstract Comparator<?> getComparator();
-		
-		public String getTitle() {
-			return title;
-		}
-		
-		public int getWidth() {
-			return width;
-		}
-		
-		public String getToolTipText(ThrustCurveMotor m) {
-			String tip = "<html>";
-			tip += "<b>" + m.toString() + "</b>";
-			tip += " (" + m.getMotorType().getDescription() + ")<br><hr>";
-			
-			String desc = m.getDescription().trim();
-			if (desc.length() > 0) {
-				tip += "<i>" + desc.replace("\n", "<br>") + "</i><br><hr>";
-			}
-			
-			tip += ("Diameter: " +
-					UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(m.getDiameter()) +
-					"<br>");
-			tip += ("Length: " +
-					UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(m.getLength()) +
-					"<br>");
-			tip += ("Maximum thrust: " +
-					UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(m.getMaxThrustEstimate()) +
-					"<br>");
-			tip += ("Average thrust: " +
-					UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(m.getAverageThrustEstimate()) +
-					"<br>");
-			tip += ("Burn time: " +
-					UnitGroup.UNITS_SHORT_TIME.getDefaultUnit()
-							.toStringUnit(m.getBurnTimeEstimate()) + "<br>");
-			tip += ("Total impulse: " +
-					UnitGroup.UNITS_IMPULSE.getDefaultUnit()
-							.toStringUnit(m.getTotalImpulseEstimate()) + "<br>");
-			tip += ("Launch mass: " +
-					UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(m.getLaunchCG().weight) +
-					"<br>");
-			tip += ("Empty mass: " +
-					UnitGroup.UNITS_MASS.getDefaultUnit()
-							.toStringUnit(m.getEmptyCG().weight));
-			return tip;
-		}
-		
-	}
-	
-	
-	/**
-	 * The JTable model.  Includes an extra motor, given in the constructor,
-	 * if it is not already in the database.
-	 */
-	private class MotorDatabaseModel extends AbstractTableModel {
-		private final ThrustCurveMotor extra;
-		
-		public MotorDatabaseModel(ThrustCurveMotor current) {
-			if (Databases.MOTOR.contains(current))
-				extra = null;
-			else
-				extra = current;
-		}
-		
-		@Override
-		public int getColumnCount() {
-			return MotorColumns.values().length;
-		}
-		
-		@Override
-		public int getRowCount() {
-			if (extra == null)
-				return Databases.MOTOR.size();
-			else
-				return Databases.MOTOR.size() + 1;
-		}
-		
-		@Override
-		public Object getValueAt(int rowIndex, int columnIndex) {
-			MotorColumns column = getColumn(columnIndex);
-			if (extra == null) {
-				return column.getValue(Databases.MOTOR.get(rowIndex));
-			} else {
-				if (rowIndex == 0)
-					return column.getValue(extra);
-				else
-					return column.getValue(Databases.MOTOR.get(rowIndex - 1));
-			}
-		}
-		
-		@Override
-		public String getColumnName(int columnIndex) {
-			return getColumn(columnIndex).getTitle();
-		}
-		
-		
-		public ThrustCurveMotor getMotor(int rowIndex) {
-			if (extra == null) {
-				return Databases.MOTOR.get(rowIndex);
-			} else {
-				if (rowIndex == 0)
-					return extra;
-				else
-					return Databases.MOTOR.get(rowIndex - 1);
-			}
-		}
-		
-		public int getIndex(ThrustCurveMotor m) {
-			if (extra == null) {
-				return Databases.MOTOR.indexOf(m);
-			} else {
-				if (extra.equals(m))
-					return 0;
-				else
-					return Databases.MOTOR.indexOf(m) + 1;
-			}
-		}
-		
-		private MotorColumns getColumn(int index) {
-			return MotorColumns.values()[index];
-		}
-	}
-	
-	
-	////////  Row filters
-	
-	/**
-	 * Abstract adapter class.
-	 */
-	private abstract class MotorRowFilter extends RowFilter<TableModel, Integer> {
-		@Override
-		public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
-			int index = entry.getIdentifier();
-			ThrustCurveMotor m = model.getMotor(index);
-			return filterByDiameter(m) && filterByString(m);
-		}
-		
-		public abstract boolean filterByDiameter(ThrustCurveMotor m);
-		
-		
-		public boolean filterByString(ThrustCurveMotor m) {
-			main: for (String s : searchTerms) {
-				for (MotorColumns col : MotorColumns.values()) {
-					String str = col.getValue(m).toString().toLowerCase();
-					if (str.indexOf(s) >= 0)
-						continue main;
-				}
-				return false;
-			}
-			return true;
-		}
-	}
-	
-	/**
-	 * Show all motors.
-	 */
-	private class MotorRowFilterAll extends MotorRowFilter {
-		@Override
-		public boolean filterByDiameter(ThrustCurveMotor m) {
-			return true;
-		}
-	}
-	
-	/**
-	 * Show motors smaller than the mount.
-	 */
-	private class MotorRowFilterSmaller extends MotorRowFilter {
-		@Override
-		public boolean filterByDiameter(ThrustCurveMotor m) {
-			return (m.getDiameter() <= diameter + 0.0004);
-		}
-	}
-	
-	/**
-	 * Show motors that fit the mount.
-	 */
-	private class MotorRowFilterExact extends MotorRowFilter {
-		@Override
-		public boolean filterByDiameter(ThrustCurveMotor m) {
-			return ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015));
-		}
-	}
-	
-}
diff --git a/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java b/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java
new file mode 100644
index 000000000..c53a63b3d
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/MotorDatabaseLoadingDialog.java
@@ -0,0 +1,79 @@
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.Timer;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.GUIUtil;
+
+public class MotorDatabaseLoadingDialog extends JDialog {
+	private static final LogHelper log = Application.getLogger();
+	
+	
+	private MotorDatabaseLoadingDialog(Window parent) {
+		super(parent, "Loading motors", ModalityType.APPLICATION_MODAL);
+		
+		JPanel panel = new JPanel(new MigLayout("fill"));
+		panel.add(new JLabel("Loading motors..."), "wrap para");
+		
+		JProgressBar progress = new JProgressBar();
+		progress.setIndeterminate(true);
+		panel.add(progress, "growx");
+		
+		this.add(panel);
+		this.pack();
+		this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+		this.setLocationByPlatform(true);
+		GUIUtil.setWindowIcons(this);
+	}
+	
+	
+	/**
+	 * Check whether the motor database is loaded and block until it is.
+	 * An uncloseable modal dialog window is opened while loading.
+	 * 
+	 * @param parent	the parent window for the dialog, or <code>null</code>
+	 */
+	public static void check(Window parent) {
+		final ThrustCurveMotorSetDatabase db = Application.getMotorSetDatabase();
+		if (db.isLoaded())
+			return;
+		
+		log.info(1, "Motor database not loaded yet, displaying dialog");
+		
+		final MotorDatabaseLoadingDialog dialog = new MotorDatabaseLoadingDialog(parent);
+		
+		final Timer timer = new Timer(100, new ActionListener() {
+			private int count = 0;
+			
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				count++;
+				if (db.isLoaded()) {
+					log.debug("Database loaded, closing dialog");
+					dialog.setVisible(false);
+				} else if (count % 10 == 0) {
+					log.debug("Database not loaded, count=" + count);
+				}
+			}
+		});
+		
+		db.setInUse();
+		timer.start();
+		dialog.setVisible(true);
+		timer.stop();
+		
+		log.debug("Motor database now loaded");
+	}
+	
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/CloseableDialog.java b/src/net/sf/openrocket/gui/dialogs/motor/CloseableDialog.java
new file mode 100644
index 000000000..48e58a0fe
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/CloseableDialog.java
@@ -0,0 +1,12 @@
+package net.sf.openrocket.gui.dialogs.motor;
+
+public interface CloseableDialog {
+	
+	/**
+	 * Close this dialog.
+	 * 
+	 * @param ok	whether "OK" should be considered to have been clicked.
+	 */
+	public void close(boolean ok);
+	
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java b/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
new file mode 100644
index 000000000..2258251f4
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
@@ -0,0 +1,112 @@
+package net.sf.openrocket.gui.dialogs.motor;
+
+
+import java.awt.Dialog;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.dialogs.MotorDatabaseLoadingDialog;
+import net.sf.openrocket.gui.dialogs.motor.thrustcurve.ThrustCurveMotorSelectionPanel;
+import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.motor.ThrustCurveMotor;
+import net.sf.openrocket.util.GUIUtil;
+
+public class MotorChooserDialog extends JDialog implements CloseableDialog {
+	
+	private final ThrustCurveMotorSelectionPanel selectionPanel;
+	
+	private boolean okClicked = false;
+	
+	
+	public MotorChooserDialog(Motor current, double delay, double diameter, Window owner) {
+		super(owner, "Select a rocket motor", Dialog.ModalityType.APPLICATION_MODAL);
+		
+		// Check that the motor database has been loaded properly
+		MotorDatabaseLoadingDialog.check(null);
+		
+
+		JPanel panel = new JPanel(new MigLayout("fill"));
+		
+		selectionPanel = new ThrustCurveMotorSelectionPanel((ThrustCurveMotor) current, delay, diameter);
+		
+		panel.add(selectionPanel, "grow, wrap para");
+		
+
+		// OK / Cancel buttons
+		
+		JButton okButton = new JButton("OK");
+		okButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				close(true);
+			}
+		});
+		panel.add(okButton, "tag ok, spanx, split");
+		
+		JButton cancelButton = new JButton("Cancel");
+		cancelButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				close(false);
+			}
+		});
+		panel.add(cancelButton, "tag cancel");
+		
+		this.add(panel);
+		
+		this.setModal(true);
+		this.pack();
+		this.setLocationByPlatform(true);
+		GUIUtil.setDisposableDialogOptions(this, okButton);
+		
+		JComponent focus = selectionPanel.getDefaultFocus();
+		if (focus != null) {
+			focus.grabFocus();
+		}
+		
+		// Set the closeable dialog after all initialization
+		selectionPanel.setCloseableDialog(this);
+	}
+	
+	
+	/**
+	 * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
+	 * 
+	 * @return	the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
+	 */
+	public Motor getSelectedMotor() {
+		if (!okClicked)
+			return null;
+		return selectionPanel.getSelectedMotor();
+	}
+	
+	/**
+	 * Return the selected ejection charge delay.
+	 * 
+	 * @return	the selected ejection charge delay.
+	 */
+	public double getSelectedDelay() {
+		return selectionPanel.getSelectedDelay();
+	}
+	
+	
+
+	@Override
+	public void close(boolean ok) {
+		okClicked = ok;
+		this.setVisible(false);
+		
+		Motor selected = getSelectedMotor();
+		if (okClicked && selected != null) {
+			selectionPanel.selectedMotor(selected);
+		}
+	}
+	
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/MotorSelector.java b/src/net/sf/openrocket/gui/dialogs/motor/MotorSelector.java
new file mode 100644
index 000000000..23bd9984c
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/MotorSelector.java
@@ -0,0 +1,38 @@
+package net.sf.openrocket.gui.dialogs.motor;
+
+import javax.swing.JComponent;
+
+import net.sf.openrocket.motor.Motor;
+
+public interface MotorSelector {
+	
+	/**
+	 * Return the currently selected motor.
+	 * 
+	 * @return		the currently selected motor, or <code>null</code> if no motor is selected.
+	 */
+	public Motor getSelectedMotor();
+	
+	/**
+	 * Return the currently selected ejection charge delay.
+	 * 
+	 * @return		the currently selected ejection charge delay.
+	 */
+	public double getSelectedDelay();
+	
+	/**
+	 * Return the component that should have the default focus in this motor selector panel.
+	 * 
+	 * @return		the component that should have default focus, or <code>null</code> for none.
+	 */
+	public JComponent getDefaultFocus();
+	
+	/**
+	 * Notify that the provided motor has been selected.  This can be used to store preference
+	 * data for later usage.
+	 * 
+	 * @param m		the motor that was selected.
+	 */
+	public void selectedMotor(Motor m);
+	
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorHolder.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorHolder.java
new file mode 100644
index 000000000..bb8113331
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/MotorHolder.java
@@ -0,0 +1,40 @@
+package net.sf.openrocket.gui.dialogs.motor.thrustcurve;
+
+import net.sf.openrocket.motor.ThrustCurveMotor;
+
+class MotorHolder {
+	
+	private final ThrustCurveMotor motor;
+	private final int index;
+	
+	public MotorHolder(ThrustCurveMotor motor, int index) {
+		this.motor = motor;
+		this.index = index;
+	}
+	
+	public ThrustCurveMotor getMotor() {
+		return motor;
+	}
+	
+	public int getIndex() {
+		return index;
+	}
+	
+	@Override
+	public String toString() {
+		return motor.getDesignation();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof MotorHolder))
+			return false;
+		MotorHolder other = (MotorHolder) obj;
+		return this.motor.equals(other.motor);
+	}
+	
+	@Override
+	public int hashCode() {
+		return motor.hashCode();
+	}
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorColumns.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorColumns.java
new file mode 100644
index 000000000..145a9956e
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorColumns.java
@@ -0,0 +1,136 @@
+package net.sf.openrocket.gui.dialogs.motor.thrustcurve;
+
+import java.text.Collator;
+import java.util.Comparator;
+
+import net.sf.openrocket.database.ThrustCurveMotorSet;
+import net.sf.openrocket.motor.DesignationComparator;
+import net.sf.openrocket.motor.ThrustCurveMotor;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.unit.Value;
+import net.sf.openrocket.unit.ValueComparator;
+
+/**
+ * Enum defining the table columns.
+ */
+enum ThrustCurveMotorColumns {
+	MANUFACTURER("Manufacturer", 100) {
+		@Override
+		public String getValue(ThrustCurveMotorSet m) {
+			return m.getManufacturer().getDisplayName();
+		}
+		
+		@Override
+		public Comparator<?> getComparator() {
+			return Collator.getInstance();
+		}
+	},
+	DESIGNATION("Designation") {
+		@Override
+		public String getValue(ThrustCurveMotorSet m) {
+			return m.getDesignation();
+		}
+		
+		@Override
+		public Comparator<?> getComparator() {
+			return new DesignationComparator();
+		}
+	},
+	TYPE("Type") {
+		@Override
+		public String getValue(ThrustCurveMotorSet m) {
+			return m.getType().getName();
+		}
+		
+		@Override
+		public Comparator<?> getComparator() {
+			return Collator.getInstance();
+		}
+	},
+	DIAMETER("Diameter") {
+		@Override
+		public Object getValue(ThrustCurveMotorSet m) {
+			return new Value(m.getDiameter(), UnitGroup.UNITS_MOTOR_DIMENSIONS);
+		}
+		
+		@Override
+		public Comparator<?> getComparator() {
+			return ValueComparator.INSTANCE;
+		}
+	},
+	LENGTH("Length") {
+		@Override
+		public Object getValue(ThrustCurveMotorSet m) {
+			return new Value(m.getLength(), UnitGroup.UNITS_MOTOR_DIMENSIONS);
+		}
+		
+		@Override
+		public Comparator<?> getComparator() {
+			return ValueComparator.INSTANCE;
+		}
+	};
+	
+
+	private final String title;
+	private final int width;
+	
+	ThrustCurveMotorColumns(String title) {
+		this(title, 50);
+	}
+	
+	ThrustCurveMotorColumns(String title, int width) {
+		this.title = title;
+		this.width = width;
+	}
+	
+	
+	public abstract Object getValue(ThrustCurveMotorSet m);
+	
+	public abstract Comparator<?> getComparator();
+	
+	public String getTitle() {
+		return title;
+	}
+	
+	public int getWidth() {
+		return width;
+	}
+	
+	public String getToolTipText(ThrustCurveMotor m) {
+		String tip = "<html>";
+		tip += "<b>" + m.toString() + "</b>";
+		tip += " (" + m.getMotorType().getDescription() + ")<br><hr>";
+		
+		String desc = m.getDescription().trim();
+		if (desc.length() > 0) {
+			tip += "<i>" + desc.replace("\n", "<br>") + "</i><br><hr>";
+		}
+		
+		tip += ("Diameter: " +
+				UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(m.getDiameter()) +
+				"<br>");
+		tip += ("Length: " +
+				UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(m.getLength()) +
+				"<br>");
+		tip += ("Maximum thrust: " +
+				UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(m.getMaxThrustEstimate()) +
+				"<br>");
+		tip += ("Average thrust: " +
+				UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(m.getAverageThrustEstimate()) +
+				"<br>");
+		tip += ("Burn time: " +
+				UnitGroup.UNITS_SHORT_TIME.getDefaultUnit()
+						.toStringUnit(m.getBurnTimeEstimate()) + "<br>");
+		tip += ("Total impulse: " +
+				UnitGroup.UNITS_IMPULSE.getDefaultUnit()
+						.toStringUnit(m.getTotalImpulseEstimate()) + "<br>");
+		tip += ("Launch mass: " +
+				UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(m.getLaunchCG().weight) +
+				"<br>");
+		tip += ("Empty mass: " +
+				UnitGroup.UNITS_MASS.getDefaultUnit()
+						.toStringUnit(m.getEmptyCG().weight));
+		return tip;
+	}
+	
+}
\ No newline at end of file
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorDatabaseModel.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorDatabaseModel.java
new file mode 100644
index 000000000..2dc92bd31
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorDatabaseModel.java
@@ -0,0 +1,51 @@
+package net.sf.openrocket.gui.dialogs.motor.thrustcurve;
+
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+import net.sf.openrocket.database.ThrustCurveMotorSet;
+
+class ThrustCurveMotorDatabaseModel extends AbstractTableModel {
+	private final List<ThrustCurveMotorSet> database;
+	
+	public ThrustCurveMotorDatabaseModel(List<ThrustCurveMotorSet> database) {
+		this.database = database;
+	}
+	
+	@Override
+	public int getColumnCount() {
+		return ThrustCurveMotorColumns.values().length;
+	}
+	
+	@Override
+	public int getRowCount() {
+		return database.size();
+	}
+	
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		ThrustCurveMotorColumns column = getColumn(columnIndex);
+		return column.getValue(database.get(rowIndex));
+	}
+	
+	@Override
+	public String getColumnName(int columnIndex) {
+		return getColumn(columnIndex).getTitle();
+	}
+	
+	
+	public ThrustCurveMotorSet getMotorSet(int rowIndex) {
+		return database.get(rowIndex);
+	}
+	
+	
+	public int getIndex(ThrustCurveMotorSet m) {
+		return database.indexOf(m);
+	}
+	
+	private ThrustCurveMotorColumns getColumn(int index) {
+		return ThrustCurveMotorColumns.values()[index];
+	}
+	
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java
new file mode 100644
index 000000000..da6fb5165
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorPlotDialog.java
@@ -0,0 +1,134 @@
+package net.sf.openrocket.gui.dialogs.motor.thrustcurve;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ThrustCurveMotorSet;
+import net.sf.openrocket.motor.ThrustCurveMotor;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.GUIUtil;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+public class ThrustCurveMotorPlotDialog extends JDialog {
+	
+	public ThrustCurveMotorPlotDialog(ThrustCurveMotorSet motorSet, ThrustCurveMotor selectedMotor, Window parent) {
+		super(parent, "Motor thrust curves", ModalityType.APPLICATION_MODAL);
+		
+		JPanel panel = new JPanel(new MigLayout("fill"));
+		
+		// Thrust curve plot
+		JFreeChart chart = ChartFactory.createXYLineChart(
+				"Motor thrust curves", // title
+				"Time / " + UnitGroup.UNITS_SHORT_TIME.getDefaultUnit().getUnit(), // xAxisLabel
+				"Thrust / " + UnitGroup.UNITS_FORCE.getDefaultUnit().getUnit(), // yAxisLabel
+				null, // dataset
+				PlotOrientation.VERTICAL,
+				true, // legend
+				true, // tooltips
+				false // urls
+				);
+		
+
+		// Add the data and formatting to the plot
+		XYPlot plot = chart.getXYPlot();
+		
+		chart.setBackgroundPaint(panel.getBackground());
+		plot.setBackgroundPaint(Color.WHITE);
+		plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
+		plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
+		
+		ChartPanel chartPanel = new ChartPanel(chart,
+				false, // properties
+				true, // save
+				false, // print
+				true, // zoom
+				true); // tooltips
+		chartPanel.setMouseWheelEnabled(true);
+		chartPanel.setEnforceFileExtensions(true);
+		chartPanel.setInitialDelay(500);
+		
+		StandardXYItemRenderer renderer = new StandardXYItemRenderer();
+		renderer.setBaseShapesVisible(true);
+		renderer.setBaseShapesFilled(true);
+		plot.setRenderer(renderer);
+		
+
+		// Create the plot data set
+		XYSeriesCollection dataset = new XYSeriesCollection();
+		List<ThrustCurveMotor> motors = motorSet.getMotors();
+		
+		// Selected thrust curve
+		int index = motors.indexOf(selectedMotor);
+		int n = 0;
+		dataset.addSeries(generateSeries(selectedMotor));
+		renderer.setSeriesStroke(n, new BasicStroke(1.5f));
+		if (index >= 0) {
+			renderer.setSeriesPaint(n, ThrustCurveMotorSelectionPanel.getColor(index));
+		}
+		n++;
+		
+		// Other thrust curves
+		for (int i = 0; i < motors.size(); i++) {
+			if (i == index)
+				continue;
+			
+			ThrustCurveMotor m = motors.get(i);
+			dataset.addSeries(generateSeries(m));
+			renderer.setSeriesStroke(n, new BasicStroke(1.5f));
+			renderer.setSeriesPaint(n, ThrustCurveMotorSelectionPanel.getColor(i));
+			renderer.setSeriesShape(n, new Rectangle());
+			n++;
+		}
+		
+		plot.setDataset(dataset);
+		
+		panel.add(chartPanel, "width 600:600:, height 400:400:, grow, wrap para");
+		
+
+		// Close button
+		JButton close = new JButton("Close");
+		close.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				ThrustCurveMotorPlotDialog.this.setVisible(false);
+			}
+		});
+		panel.add(close, "right, tag close");
+		
+
+		this.add(panel);
+		
+		this.pack();
+		GUIUtil.setDisposableDialogOptions(this, null);
+	}
+	
+	
+	private XYSeries generateSeries(ThrustCurveMotor motor) {
+		XYSeries series = new XYSeries(motor.getManufacturer() + " " + motor.getDesignation());
+		double[] time = motor.getTimePoints();
+		double[] thrust = motor.getThrustPoints();
+		
+		for (int j = 0; j < time.length; j++) {
+			series.add(time[j], thrust[j]);
+		}
+		return series;
+	}
+}
diff --git a/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java
new file mode 100644
index 000000000..038359d78
--- /dev/null
+++ b/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java
@@ -0,0 +1,892 @@
+package net.sf.openrocket.gui.dialogs.motor.thrustcurve;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Font;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.BorderFactory;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTable;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.RowFilter;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ThrustCurveMotorSet;
+import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.components.StyledLabel.Style;
+import net.sf.openrocket.gui.dialogs.motor.CloseableDialog;
+import net.sf.openrocket.gui.dialogs.motor.MotorSelector;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.motor.MotorDigest;
+import net.sf.openrocket.motor.ThrustCurveMotor;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.util.Icons;
+import net.sf.openrocket.util.Prefs;
+
+import org.jfree.chart.ChartColor;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.title.TextTitle;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelector {
+	private static final LogHelper log = Application.getLogger();
+	
+	private static final int SHOW_ALL = 0;
+	private static final int SHOW_SMALLER = 1;
+	private static final int SHOW_EXACT = 2;
+	private static final String[] SHOW_DESCRIPTIONS = {
+			"Show all motors",
+			"Show motors with diameter less than that of the motor mount",
+			"Show motors with diameter equal to that of the motor mount"
+	};
+	private static final int SHOW_MAX = 2;
+	
+	private static final int ZOOM_ICON_POSITION_NEGATIVE_X = 50;
+	private static final int ZOOM_ICON_POSITION_POSITIVE_Y = 12;
+	
+	private static final Paint[] CURVE_COLORS = ChartColor.createDefaultPaintArray();
+	
+	private static final Color NO_COMMENT_COLOR = Color.GRAY;
+	private static final Color WITH_COMMENT_COLOR = Color.BLACK;
+	
+	private final List<ThrustCurveMotorSet> database;
+	
+	private final double diameter;
+	private CloseableDialog dialog = null;
+	
+
+	private final ThrustCurveMotorDatabaseModel model;
+	private final JTable table;
+	private final TableRowSorter<TableModel> sorter;
+	
+	private final JTextField searchField;
+	private String[] searchTerms = new String[0];
+	
+
+	private final JLabel curveSelectionLabel;
+	private final JComboBox curveSelectionBox;
+	private final DefaultComboBoxModel curveSelectionModel;
+	
+	private final JLabel totalImpulseLabel;
+	private final JLabel avgThrustLabel;
+	private final JLabel maxThrustLabel;
+	private final JLabel burnTimeLabel;
+	private final JLabel launchMassLabel;
+	private final JLabel emptyMassLabel;
+	private final JLabel dataPointsLabel;
+	
+	private final JTextArea comment;
+	private final Font noCommentFont;
+	private final Font withCommentFont;
+	
+	private final JFreeChart chart;
+	private final ChartPanel chartPanel;
+	private final JLabel zoomIcon;
+	
+	private final JComboBox delayBox;
+	
+	private ThrustCurveMotor selectedMotor;
+	private ThrustCurveMotorSet selectedMotorSet;
+	private double selectedDelay;
+	
+	
+	/**
+	 * Sole constructor.
+	 * 
+	 * @param current	the currently selected ThrustCurveMotor, or <code>null</code> for none.
+	 * @param delay		the currently selected ejection charge delay.
+	 * @param diameter	the diameter of the motor mount.
+	 */
+	public ThrustCurveMotorSelectionPanel(ThrustCurveMotor current, double delay, double diameter) {
+		super(new MigLayout("fill", "[grow][]"));
+		
+		this.diameter = diameter;
+		
+
+		// Construct the database (adding the current motor if not in the db already)
+		List<ThrustCurveMotorSet> db;
+		db = Application.getMotorSetDatabase().getMotorSets();
+		
+		// If current motor is not found in db, add a new ThrustCurveMotorSet containing it
+		if (current != null) {
+			selectedMotor = current;
+			for (ThrustCurveMotorSet motorSet : db) {
+				if (motorSet.getMotors().contains(current)) {
+					selectedMotorSet = motorSet;
+					break;
+				}
+			}
+			if (selectedMotorSet == null) {
+				db = new ArrayList<ThrustCurveMotorSet>(db);
+				ThrustCurveMotorSet extra = new ThrustCurveMotorSet();
+				extra.addMotor(current);
+				selectedMotorSet = extra;
+				db.add(extra);
+				Collections.sort(db);
+			}
+		}
+		database = db;
+		
+
+
+		////  GUI
+		
+		JPanel panel;
+		JLabel label;
+		
+		panel = new JPanel(new MigLayout("fill"));
+		this.add(panel, "grow");
+		
+
+
+		// Selection label
+		label = new StyledLabel("Select rocket motor:", Style.BOLD);
+		panel.add(label, "spanx, wrap para");
+		
+		// Diameter selection
+		JComboBox filterComboBox = new JComboBox(SHOW_DESCRIPTIONS);
+		filterComboBox.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				JComboBox cb = (JComboBox) e.getSource();
+				int sel = cb.getSelectedIndex();
+				if ((sel < 0) || (sel > SHOW_MAX))
+					sel = SHOW_ALL;
+				switch (sel) {
+				case SHOW_ALL:
+							sorter.setRowFilter(new MotorRowFilterAll());
+							break;
+						
+						case SHOW_SMALLER:
+							sorter.setRowFilter(new MotorRowFilterSmaller());
+							break;
+						
+						case SHOW_EXACT:
+							sorter.setRowFilter(new MotorRowFilterExact());
+							break;
+						
+						default:
+							assert (false) : "Should not occur.";
+						}
+						Prefs.putChoise("MotorDiameterMatch", sel);
+						scrollSelectionVisible();
+					}
+		});
+		panel.add(filterComboBox, "spanx, growx, wrap para");
+		
+
+
+		// Motor selection table
+		model = new ThrustCurveMotorDatabaseModel(database);
+		table = new JTable(model);
+		
+
+		// Set comparators and widths
+		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		sorter = new TableRowSorter<TableModel>(model);
+		for (int i = 0; i < ThrustCurveMotorColumns.values().length; i++) {
+			ThrustCurveMotorColumns column = ThrustCurveMotorColumns.values()[i];
+			sorter.setComparator(i, column.getComparator());
+			table.getColumnModel().getColumn(i).setPreferredWidth(column.getWidth());
+		}
+		table.setRowSorter(sorter);
+		
+		// Set selection and double-click listeners
+		table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				int row = table.getSelectedRow();
+				if (row >= 0) {
+					row = table.convertRowIndexToModel(row);
+					ThrustCurveMotorSet motorSet = model.getMotorSet(row);
+					log.user("Selected table row " + row + ": " + motorSet);
+					if (motorSet != selectedMotorSet) {
+						select(selectMotor(motorSet));
+					}
+				} else {
+					log.user("Selected table row " + row + ", nothing selected");
+				}
+			}
+		});
+		table.addMouseListener(new MouseAdapter() {
+			@Override
+			public void mouseClicked(MouseEvent e) {
+				if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
+					if (dialog != null) {
+						dialog.close(true);
+					}
+				}
+			}
+		});
+		
+
+		JScrollPane scrollpane = new JScrollPane();
+		scrollpane.setViewportView(table);
+		panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para");
+		
+
+
+
+		// Motor mount diameter label
+		label = new StyledLabel("Motor mount diameter: " +
+				UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(diameter));
+		panel.add(label, "gapright 30lp, spanx, split");
+		
+
+
+		// Search field
+		label = new StyledLabel("Search:");
+		panel.add(label, "");
+		
+		searchField = new JTextField();
+		searchField.getDocument().addDocumentListener(new DocumentListener() {
+			@Override
+			public void changedUpdate(DocumentEvent e) {
+				update();
+			}
+			
+			@Override
+			public void insertUpdate(DocumentEvent e) {
+				update();
+			}
+			
+			@Override
+			public void removeUpdate(DocumentEvent e) {
+				update();
+			}
+			
+			private void update() {
+				String text = searchField.getText().trim();
+				String[] split = text.split("\\s+");
+				ArrayList<String> list = new ArrayList<String>();
+				for (String s : split) {
+					s = s.trim().toLowerCase();
+					if (s.length() > 0) {
+						list.add(s);
+					}
+				}
+				searchTerms = list.toArray(new String[0]);
+				sorter.sort();
+				scrollSelectionVisible();
+			}
+		});
+		panel.add(searchField, "growx, wrap");
+		
+
+
+		// Vertical split
+		this.add(panel, "grow");
+		this.add(new JSeparator(JSeparator.VERTICAL), "growy, gap para para");
+		panel = new JPanel(new MigLayout("fill"));
+		
+
+
+		// Thrust curve selection
+		curveSelectionLabel = new JLabel("Select thrust curve:");
+		panel.add(curveSelectionLabel);
+		
+		curveSelectionModel = new DefaultComboBoxModel();
+		curveSelectionBox = new JComboBox(curveSelectionModel);
+		curveSelectionBox.setRenderer(new CurveSelectionRenderer(curveSelectionBox.getRenderer()));
+		curveSelectionBox.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				Object value = curveSelectionBox.getSelectedItem();
+				if (value != null) {
+					select(((MotorHolder) value).getMotor());
+				}
+			}
+		});
+		panel.add(curveSelectionBox, "growx, wrap para");
+		
+
+
+
+
+		// Ejection charge delay
+		panel.add(new JLabel("Ejection charge delay:"));
+		
+		delayBox = new JComboBox();
+		delayBox.setEditable(true);
+		delayBox.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				JComboBox cb = (JComboBox) e.getSource();
+				String sel = (String) cb.getSelectedItem();
+				if (sel.equalsIgnoreCase("None")) {
+					selectedDelay = Motor.PLUGGED;
+				} else {
+					try {
+						selectedDelay = Double.parseDouble(sel);
+					} catch (NumberFormatException ignore) {
+					}
+				}
+				setDelays(false);
+			}
+		});
+		panel.add(delayBox, "growx, wrap rel");
+		panel.add(new StyledLabel("(Number of seconds or \"None\")", -3), "skip, wrap para");
+		setDelays(false);
+		
+
+		panel.add(new JSeparator(), "spanx, growx, wrap para");
+		
+
+
+		// Thrust curve info
+		panel.add(new JLabel("Total impulse:"));
+		totalImpulseLabel = new JLabel();
+		panel.add(totalImpulseLabel, "wrap");
+		
+		panel.add(new JLabel("Avg. thrust:"));
+		avgThrustLabel = new JLabel();
+		panel.add(avgThrustLabel, "wrap");
+		
+		panel.add(new JLabel("Max. thrust:"));
+		maxThrustLabel = new JLabel();
+		panel.add(maxThrustLabel, "wrap");
+		
+		panel.add(new JLabel("Burn time:"));
+		burnTimeLabel = new JLabel();
+		panel.add(burnTimeLabel, "wrap");
+		
+		panel.add(new JLabel("Launch mass:"));
+		launchMassLabel = new JLabel();
+		panel.add(launchMassLabel, "wrap");
+		
+		panel.add(new JLabel("Empty mass:"));
+		emptyMassLabel = new JLabel();
+		panel.add(emptyMassLabel, "wrap");
+		
+		panel.add(new JLabel("Data points:"));
+		dataPointsLabel = new JLabel();
+		panel.add(dataPointsLabel, "wrap para");
+		
+
+		comment = new JTextArea(5, 5);
+		GUIUtil.changeFontSize(comment, -2);
+		withCommentFont = comment.getFont();
+		noCommentFont = withCommentFont.deriveFont(Font.ITALIC);
+		comment.setLineWrap(true);
+		comment.setWrapStyleWord(true);
+		comment.setEditable(false);
+		scrollpane = new JScrollPane(comment);
+		panel.add(scrollpane, "spanx, growx, wrap para");
+		
+
+
+
+		// Thrust curve plot
+		chart = ChartFactory.createXYLineChart(
+				null, // title
+				null, // xAxisLabel
+				null, // yAxisLabel
+				null, // dataset
+				PlotOrientation.VERTICAL,
+				false, // legend
+				false, // tooltips
+				false // urls
+				);
+		
+
+		// Add the data and formatting to the plot
+		XYPlot plot = chart.getXYPlot();
+		
+		changeLabelFont(plot.getRangeAxis(), -2);
+		changeLabelFont(plot.getDomainAxis(), -2);
+		
+		chart.setTitle(new TextTitle("Thrust curve:", this.getFont()));
+		chart.setBackgroundPaint(this.getBackground());
+		plot.setBackgroundPaint(Color.WHITE);
+		plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
+		plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
+		
+		chartPanel = new ChartPanel(chart,
+				false, // properties
+				false, // save
+				false, // print
+				false, // zoom
+				false); // tooltips
+		chartPanel.setMouseZoomable(false);
+		chartPanel.setPopupMenu(null);
+		chartPanel.setMouseWheelEnabled(false);
+		chartPanel.setRangeZoomable(false);
+		chartPanel.setDomainZoomable(false);
+		
+		chartPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+		chartPanel.addMouseListener(new MouseAdapter() {
+			@Override
+			public void mouseClicked(MouseEvent e) {
+				if (selectedMotor == null || selectedMotorSet == null)
+					return;
+				if (e.getButton() == MouseEvent.BUTTON1) {
+					// Open plot dialog
+					ThrustCurveMotorPlotDialog plotDialog = new ThrustCurveMotorPlotDialog(selectedMotorSet, selectedMotor,
+							SwingUtilities.getWindowAncestor(ThrustCurveMotorSelectionPanel.this));
+					plotDialog.setVisible(true);
+				}
+			}
+		});
+		
+		JLayeredPane layer = new CustomLayeredPane();
+		
+		layer.setBorder(BorderFactory.createLineBorder(Color.BLUE));
+		
+		layer.add(chartPanel, (Integer) 0);
+		
+		zoomIcon = new JLabel(Icons.ZOOM_IN);
+		zoomIcon.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+		layer.add(zoomIcon, (Integer) 1);
+		
+
+		panel.add(layer, "width 300:300:, height 180:180:, grow, spanx");
+		
+
+
+		this.add(panel, "grow");
+		
+
+
+		// Sets the filter:
+		int showMode = Prefs.getChoise("MotorDiameterMatch", SHOW_MAX, SHOW_EXACT);
+		filterComboBox.setSelectedIndex(showMode);
+		
+
+		// Update the panel data
+		updateData();
+		selectedDelay = delay;
+		setDelays(false);
+		
+	}
+	
+	
+
+	@Override
+	public Motor getSelectedMotor() {
+		return selectedMotor;
+	}
+	
+	
+	@Override
+	public double getSelectedDelay() {
+		return selectedDelay;
+	}
+	
+	
+	@Override
+	public JComponent getDefaultFocus() {
+		return searchField;
+	}
+	
+	@Override
+	public void selectedMotor(Motor motorSelection) {
+		if (!(motorSelection instanceof ThrustCurveMotor)) {
+			log.error("Received argument that was not ThrustCurveMotor: " + motorSelection);
+			return;
+		}
+		
+		ThrustCurveMotor motor = (ThrustCurveMotor) motorSelection;
+		ThrustCurveMotorSet set = findMotorSet(motor);
+		if (set == null) {
+			log.error("Could not find set for motor:" + motorSelection);
+			return;
+		}
+		
+		// Store selected motor in preferences node, set all others to false
+		Preferences prefs = Prefs.getNode(Prefs.PREFERRED_THRUST_CURVE_MOTOR_NODE);
+		for (ThrustCurveMotor m : set.getMotors()) {
+			String digest = MotorDigest.digestMotor(m);
+			prefs.putBoolean(digest, m == motor);
+		}
+	}
+	
+	public void setCloseableDialog(CloseableDialog dialog) {
+		this.dialog = dialog;
+	}
+	
+	
+
+	private void changeLabelFont(ValueAxis axis, float size) {
+		Font font = axis.getTickLabelFont();
+		font = font.deriveFont(font.getSize2D() + size);
+		axis.setTickLabelFont(font);
+	}
+	
+	
+	/**
+	 * Called when a different motor is selected from within the panel.
+	 */
+	private void select(ThrustCurveMotor motor) {
+		if (selectedMotor == motor)
+			return;
+		
+		ThrustCurveMotorSet set = findMotorSet(motor);
+		if (set == null) {
+			throw new BugException("Could not find motor from database, motor=" + motor);
+		}
+		
+		boolean updateDelays = (selectedMotorSet != set);
+		
+		selectedMotor = motor;
+		selectedMotorSet = set;
+		updateData();
+		if (updateDelays) {
+			setDelays(true);
+		}
+	}
+	
+	
+	private void updateData() {
+		
+		if (selectedMotorSet == null) {
+			// No motor selected
+			curveSelectionModel.removeAllElements();
+			curveSelectionBox.setEnabled(false);
+			curveSelectionLabel.setEnabled(false);
+			totalImpulseLabel.setText("");
+			avgThrustLabel.setText("");
+			maxThrustLabel.setText("");
+			burnTimeLabel.setText("");
+			launchMassLabel.setText("");
+			emptyMassLabel.setText("");
+			dataPointsLabel.setText("");
+			setComment("");
+			chart.getXYPlot().setDataset(new XYSeriesCollection());
+			return;
+		}
+		
+
+		List<ThrustCurveMotor> motors = selectedMotorSet.getMotors();
+		final int index = motors.indexOf(selectedMotor);
+		
+		curveSelectionModel.removeAllElements();
+		for (int i = 0; i < motors.size(); i++) {
+			curveSelectionModel.addElement(new MotorHolder(motors.get(i), i));
+		}
+		curveSelectionBox.setSelectedIndex(index);
+		
+		if (motors.size() > 1) {
+			curveSelectionBox.setEnabled(true);
+			curveSelectionLabel.setEnabled(true);
+		} else {
+			curveSelectionBox.setEnabled(false);
+			curveSelectionLabel.setEnabled(false);
+		}
+		
+		totalImpulseLabel.setText(UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(
+				selectedMotor.getTotalImpulseEstimate()));
+		avgThrustLabel.setText(UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(
+				selectedMotor.getAverageThrustEstimate()));
+		maxThrustLabel.setText(UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(
+				selectedMotor.getMaxThrustEstimate()));
+		burnTimeLabel.setText(UnitGroup.UNITS_SHORT_TIME.getDefaultUnit().toStringUnit(
+				selectedMotor.getBurnTimeEstimate()));
+		launchMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
+				selectedMotor.getLaunchCG().weight));
+		emptyMassLabel.setText(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
+				selectedMotor.getEmptyCG().weight));
+		dataPointsLabel.setText("" + (selectedMotor.getTimePoints().length - 1));
+		
+		setComment(selectedMotor.getDescription());
+		
+
+		// Update the plot
+		XYPlot plot = chart.getXYPlot();
+		
+		XYSeriesCollection dataset = new XYSeriesCollection();
+		for (int i = 0; i < motors.size(); i++) {
+			ThrustCurveMotor m = motors.get(i);
+			
+			XYSeries series = new XYSeries("Thrust");
+			double[] time = m.getTimePoints();
+			double[] thrust = m.getThrustPoints();
+			
+			for (int j = 0; j < time.length; j++) {
+				series.add(time[j], thrust[j]);
+			}
+			
+			dataset.addSeries(series);
+			
+			boolean selected = (i == index);
+			plot.getRenderer().setSeriesStroke(i, new BasicStroke(selected ? 3 : 1));
+			plot.getRenderer().setSeriesPaint(i, getColor(i));
+		}
+		
+		plot.setDataset(dataset);
+	}
+	
+	
+	private void setComment(String s) {
+		s = s.trim();
+		if (s.length() == 0) {
+			comment.setText("No description available.");
+			comment.setFont(noCommentFont);
+			comment.setForeground(NO_COMMENT_COLOR);
+		} else {
+			comment.setText(s);
+			comment.setFont(withCommentFont);
+			comment.setForeground(WITH_COMMENT_COLOR);
+		}
+		comment.setCaretPosition(0);
+	}
+	
+	private void scrollSelectionVisible() {
+		if (selectedMotorSet != null) {
+			int index = table.convertRowIndexToView(model.getIndex(selectedMotorSet));
+			System.out.println("index=" + index);
+			table.getSelectionModel().setSelectionInterval(index, index);
+			Rectangle rect = table.getCellRect(index, 0, true);
+			rect = new Rectangle(rect.x, rect.y - 100, rect.width, rect.height + 200);
+			table.scrollRectToVisible(rect);
+		}
+	}
+	
+	
+	public static Color getColor(int index) {
+		return (Color) CURVE_COLORS[index % CURVE_COLORS.length];
+	}
+	
+	
+	/**
+	 * Find the ThrustCurveMotorSet that contains a motor.
+	 * 
+	 * @param motor		the motor to look for.
+	 * @return			the ThrustCurveMotorSet, or null if not found.
+	 */
+	private ThrustCurveMotorSet findMotorSet(ThrustCurveMotor motor) {
+		for (ThrustCurveMotorSet set : database) {
+			if (set.getMotors().contains(motor)) {
+				return set;
+			}
+		}
+		
+		return null;
+	}
+	
+	
+
+	/**
+	 * Select the default motor from this ThrustCurveMotorSet.  This uses primarily motors
+	 * that the user has previously used, and secondarily a heuristic method of selecting which
+	 * thrust curve seems to be better or more reliable.
+	 * 
+	 * @param set	the motor set
+	 * @return		the default motor in this set
+	 */
+	private ThrustCurveMotor selectMotor(ThrustCurveMotorSet set) {
+		if (set.getMotorCount() == 0) {
+			throw new BugException("Attempting to select motor from empty ThrustCurveMotorSet: " + set);
+		}
+		if (set.getMotorCount() == 1) {
+			return set.getMotors().get(0);
+		}
+		
+		// Find which motor has been used the most recently
+		Preferences prefs = Prefs.getNode(Prefs.PREFERRED_THRUST_CURVE_MOTOR_NODE);
+		for (ThrustCurveMotor m : set.getMotors()) {
+			String digest = MotorDigest.digestMotor(m);
+			if (prefs.getBoolean(digest, false)) {
+				return m;
+			}
+		}
+		
+		// No motor has been used, use heuristics to select motor
+		// TODO: CRITICAL: Heuristics
+		return set.getMotors().get(0);
+	}
+	
+	
+	/**
+	 * Set the values in the delay combo box.  If <code>reset</code> is <code>true</code>
+	 * then sets the selected value as the value closest to selectedDelay, otherwise
+	 * leaves selection alone.
+	 */
+	private void setDelays(boolean reset) {
+		if (selectedMotor == null) {
+			
+			delayBox.setModel(new DefaultComboBoxModel(new String[] { "None" }));
+			delayBox.setSelectedIndex(0);
+			
+		} else {
+			
+			List<Double> delays = selectedMotorSet.getDelays();
+			String[] delayStrings = new String[delays.size()];
+			double currentDelay = selectedDelay; // Store current setting locally
+			
+			for (int i = 0; i < delays.size(); i++) {
+				delayStrings[i] = ThrustCurveMotor.getDelayString(delays.get(i), "None");
+			}
+			delayBox.setModel(new DefaultComboBoxModel(delayStrings));
+			
+			if (reset) {
+				
+				// Find and set the closest value
+				double closest = Double.NaN;
+				for (int i = 0; i < delays.size(); i++) {
+					// if-condition to always become true for NaN
+					if (!(Math.abs(delays.get(i) - currentDelay) > Math.abs(closest - currentDelay))) {
+						closest = delays.get(i);
+					}
+				}
+				if (!Double.isNaN(closest)) {
+					selectedDelay = closest;
+					delayBox.setSelectedItem(ThrustCurveMotor.getDelayString(closest, "None"));
+				} else {
+					delayBox.setSelectedItem("None");
+				}
+				
+			} else {
+				
+				selectedDelay = currentDelay;
+				delayBox.setSelectedItem(ThrustCurveMotor.getDelayString(currentDelay, "None"));
+				
+			}
+			
+		}
+	}
+	
+	
+
+
+	//////////////////////
+	
+
+	private class CurveSelectionRenderer implements ListCellRenderer {
+		
+		private final ListCellRenderer renderer;
+		
+		public CurveSelectionRenderer(ListCellRenderer renderer) {
+			this.renderer = renderer;
+		}
+		
+		@Override
+		public Component getListCellRendererComponent(JList list, Object value, int index,
+				boolean isSelected, boolean cellHasFocus) {
+			
+			Component c = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+			if (value instanceof MotorHolder) {
+				MotorHolder m = (MotorHolder) value;
+				c.setForeground(getColor(m.getIndex()));
+			}
+			
+			return c;
+		}
+		
+	}
+	
+	
+	////////  Row filters
+	
+	/**
+	 * Abstract adapter class.
+	 */
+	private abstract class MotorRowFilter extends RowFilter<TableModel, Integer> {
+		@Override
+		public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
+			int index = entry.getIdentifier();
+			ThrustCurveMotorSet m = model.getMotorSet(index);
+			return filterByDiameter(m) && filterByString(m);
+		}
+		
+		public abstract boolean filterByDiameter(ThrustCurveMotorSet m);
+		
+		
+		public boolean filterByString(ThrustCurveMotorSet m) {
+			main: for (String s : searchTerms) {
+				for (ThrustCurveMotorColumns col : ThrustCurveMotorColumns.values()) {
+					String str = col.getValue(m).toString().toLowerCase();
+					if (str.indexOf(s) >= 0)
+						continue main;
+				}
+				return false;
+			}
+			return true;
+		}
+	}
+	
+	/**
+	 * Show all motors.
+	 */
+	private class MotorRowFilterAll extends MotorRowFilter {
+		@Override
+		public boolean filterByDiameter(ThrustCurveMotorSet m) {
+			return true;
+		}
+	}
+	
+	/**
+	 * Show motors smaller than the mount.
+	 */
+	private class MotorRowFilterSmaller extends MotorRowFilter {
+		@Override
+		public boolean filterByDiameter(ThrustCurveMotorSet m) {
+			return (m.getDiameter() <= diameter + 0.0004);
+		}
+	}
+	
+	/**
+	 * Show motors that fit the mount.
+	 */
+	private class MotorRowFilterExact extends MotorRowFilter {
+		@Override
+		public boolean filterByDiameter(ThrustCurveMotorSet m) {
+			return ((m.getDiameter() <= diameter + 0.0004) && (m.getDiameter() >= diameter - 0.0015));
+		}
+	}
+	
+	
+	/**
+	 * Custom layered pane that sets the bounds of the components on every layout.
+	 */
+	public class CustomLayeredPane extends JLayeredPane {
+		@Override
+		public void doLayout() {
+			synchronized (getTreeLock()) {
+				int w = getWidth();
+				int h = getHeight();
+				chartPanel.setBounds(0, 0, w, h);
+				zoomIcon.setBounds(w - ZOOM_ICON_POSITION_NEGATIVE_X, ZOOM_ICON_POSITION_POSITIVE_Y, 50, 50);
+			}
+		}
+	}
+}
diff --git a/src/net/sf/openrocket/gui/main/BasicFrame.java b/src/net/sf/openrocket/gui/main/BasicFrame.java
index 42aebf2d2..aba539863 100644
--- a/src/net/sf/openrocket/gui/main/BasicFrame.java
+++ b/src/net/sf/openrocket/gui/main/BasicFrame.java
@@ -75,16 +75,19 @@ import net.sf.openrocket.gui.dialogs.BugReportDialog;
 import net.sf.openrocket.gui.dialogs.ComponentAnalysisDialog;
 import net.sf.openrocket.gui.dialogs.ExampleDesignDialog;
 import net.sf.openrocket.gui.dialogs.LicenseDialog;
+import net.sf.openrocket.gui.dialogs.MotorDatabaseLoadingDialog;
 import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
 import net.sf.openrocket.gui.dialogs.WarningDialog;
 import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 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.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Icons;
@@ -95,33 +98,33 @@ import net.sf.openrocket.util.SaveFileWorker;
 import net.sf.openrocket.util.TestRockets;
 
 public class BasicFrame extends JFrame {
-	private static final long serialVersionUID = 1L;
-
+	private static final LogHelper log = Application.getLogger();
+	
 	/**
 	 * The RocketLoader instance used for loading all rocket designs.
 	 */
 	private static final RocketLoader ROCKET_LOADER = new GeneralRocketLoader();
 	
 	private static final RocketSaver ROCKET_SAVER = new OpenRocketSaver();
-
 	
+
 	// FileFilters for different types of rocket design files
 	private static final FileFilter ALL_DESIGNS_FILTER =
-		new SimpleFileFilter("All rocket designs (*.ork; *.rkt)", 
-				".ork", ".ork.gz", ".rkt", ".rkt.gz");
+			new SimpleFileFilter("All rocket designs (*.ork; *.rkt)",
+					".ork", ".ork.gz", ".rkt", ".rkt.gz");
 	
-	private static final FileFilter OPENROCKET_DESIGN_FILTER = 
-		new SimpleFileFilter("OpenRocket designs (*.ork)", ".ork", ".ork.gz");
+	private static final FileFilter OPENROCKET_DESIGN_FILTER =
+			new SimpleFileFilter("OpenRocket designs (*.ork)", ".ork", ".ork.gz");
 	
-	private static final FileFilter ROCKSIM_DESIGN_FILTER = 
-		new SimpleFileFilter("RockSim designs (*.rkt)", ".rkt", ".rkt.gz");
-		
+	private static final FileFilter ROCKSIM_DESIGN_FILTER =
+			new SimpleFileFilter("RockSim designs (*.rkt)", ".rkt", ".rkt.gz");
 	
+
+
+
+	public static final int COMPONENT_TAB = 0;
+	public static final int SIMULATION_TAB = 1;
 	
-    
-    public static final int COMPONENT_TAB = 0;
-    public static final int SIMULATION_TAB = 1;
-    
 
 	/**
 	 * List of currently open frames.  When the list goes empty
@@ -129,18 +132,18 @@ public class BasicFrame extends JFrame {
 	 */
 	private static final ArrayList<BasicFrame> frames = new ArrayList<BasicFrame>();
 	
-	
-	
-	
-	
+
+
+
+
 	/**
 	 * Whether "New" and "Open" should replace this frame.
 	 * Should be set to false on the first rocket modification.
 	 */
 	private boolean replaceable = false;
 	
-	
-	
+
+
 	private final OpenRocketDocument document;
 	private final Rocket rocket;
 	
@@ -156,7 +159,7 @@ public class BasicFrame extends JFrame {
 	private final RocketActions actions;
 	
 	
-	
+
 	/**
 	 * Sole constructor.  Creates a new frame based on the supplied document
 	 * and adds it to the current frames list.
@@ -164,12 +167,13 @@ public class BasicFrame extends JFrame {
 	 * @param document	the document to show.
 	 */
 	public BasicFrame(OpenRocketDocument document) {
-
+		log.debug("Instantiating new BasicFrame");
+		
 		this.document = document;
 		this.rocket = document.getRocket();
 		this.rocket.getDefaultConfiguration().setAllStages();
 		
-		
+
 		// Set replaceable flag to false at first modification
 		rocket.addComponentChangeListener(new ComponentChangeListener() {
 			public void componentChanged(ComponentChangeEvent e) {
@@ -178,7 +182,7 @@ public class BasicFrame extends JFrame {
 			}
 		});
 		
-		
+
 		// Create the component tree selection model that will be used
 		componentSelectionModel = new DefaultTreeSelectionModel();
 		componentSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
@@ -192,16 +196,18 @@ public class BasicFrame extends JFrame {
 		selectionModel.attachComponentTreeSelectionModel(componentSelectionModel);
 		selectionModel.attachSimulationListSelectionModel(simulationSelectionModel);
 		
-		
+
 		actions = new RocketActions(document, selectionModel, this);
 		
+
+		log.debug("Constructing the BasicFrame UI");
 		
 		// The main vertical split pane		
 		JSplitPane vertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true);
 		vertical.setResizeWeight(0.5);
 		this.add(vertical);
-
 		
+
 		// The top tabbed pane
 		tabbedPane = new JTabbedPane();
 		tabbedPane.addTab("Rocket design", null, designTab());
@@ -215,13 +221,13 @@ public class BasicFrame extends JFrame {
 		
 		rocketpanel = new RocketPanel(document);
 		vertical.setBottomComponent(rocketpanel);
-
+		
 		rocketpanel.setSelectionModel(tree.getSelectionModel());
+		
 
-					
 		createMenu();
 		
-		
+
 		rocket.addComponentChangeListener(new ComponentChangeListener() {
 			public void componentChanged(ComponentChangeEvent e) {
 				setTitle();
@@ -230,12 +236,12 @@ public class BasicFrame extends JFrame {
 		
 		setTitle();
 		this.pack();
-
+		
 		Dimension size = Prefs.getWindowSize(this.getClass());
 		if (size == null) {
 			size = Toolkit.getDefaultToolkit().getScreenSize();
-			size.width = size.width*9/10;
-			size.height = size.height*9/10;
+			size.width = size.width * 9 / 10;
+			size.height = size.height * 9 / 10;
 		}
 		this.setSize(size);
 		this.addComponentListener(new ComponentAdapter() {
@@ -245,7 +251,7 @@ public class BasicFrame extends JFrame {
 			}
 		});
 		this.setLocationByPlatform(true);
-
+		
 		GUIUtil.setWindowIcons(this);
 		
 		this.validate();
@@ -258,6 +264,8 @@ public class BasicFrame extends JFrame {
 			}
 		});
 		frames.add(this);
+		
+		log.debug("BasicFrame instantiation complete");
 	}
 	
 	
@@ -267,17 +275,17 @@ public class BasicFrame extends JFrame {
 	 * for adding components.
 	 */
 	private JComponent designTab() {
-		JSplitPane horizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true);
+		JSplitPane horizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
 		horizontal.setResizeWeight(0.5);
-
+		
 
 		//  Upper-left segment, component tree
-
-		JPanel panel = new JPanel(new MigLayout("fill, flowy","","[grow]"));
-
+		
+		JPanel panel = new JPanel(new MigLayout("fill, flowy", "", "[grow]"));
+		
 		tree = new ComponentTree(rocket);
 		tree.setSelectionModel(componentSelectionModel);
-
+		
 		// Remove JTree key events that interfere with menu accelerators
 		InputMap im = SwingUtilities.getUIInputMap(tree, JComponent.WHEN_FOCUSED);
 		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK), null);
@@ -287,27 +295,27 @@ public class BasicFrame extends JFrame {
 		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK), null);
 		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), null);
 		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK), null);
-
-
 		
+
+
 		// Double-click opens config dialog
 		MouseListener ml = new MouseAdapter() {
 			@Override
 			public void mousePressed(MouseEvent e) {
 				int selRow = tree.getRowForLocation(e.getX(), e.getY());
 				TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
-				if(selRow != -1) {
-					if((e.getClickCount() == 2) && !ComponentConfigDialog.isDialogVisible()) {
+				if (selRow != -1) {
+					if ((e.getClickCount() == 2) && !ComponentConfigDialog.isDialogVisible()) {
 						// Double-click
-						RocketComponent c = (RocketComponent)selPath.getLastPathComponent();
-						ComponentConfigDialog.showDialog(BasicFrame.this, 
+						RocketComponent c = (RocketComponent) selPath.getLastPathComponent();
+						ComponentConfigDialog.showDialog(BasicFrame.this,
 								BasicFrame.this.document, c);
 					}
 				}
 			}
 		};
 		tree.addMouseListener(ml);
-
+		
 		// Update dialog when selection is changed
 		componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() {
 			public void valueChanged(TreeSelectionEvent e) {
@@ -319,62 +327,62 @@ public class BasicFrame extends JFrame {
 				
 				if (!ComponentConfigDialog.isDialogVisible())
 					return;
-				RocketComponent c = (RocketComponent)path.getLastPathComponent();
-				ComponentConfigDialog.showDialog(BasicFrame.this, 
+				RocketComponent c = (RocketComponent) path.getLastPathComponent();
+				ComponentConfigDialog.showDialog(BasicFrame.this,
 						BasicFrame.this.document, c);
 			}
 		});
-
+		
 		// Place tree inside scroll pane
 		JScrollPane scroll = new JScrollPane(tree);
-		panel.add(scroll,"spany, grow, wrap");
-		
+		panel.add(scroll, "spany, grow, wrap");
 		
+
 		// Buttons
 		JButton button = new JButton(actions.getMoveUpAction());
-		panel.add(button,"sizegroup buttons, aligny 65%");
+		panel.add(button, "sizegroup buttons, aligny 65%");
 		
 		button = new JButton(actions.getMoveDownAction());
-		panel.add(button,"sizegroup buttons, aligny 0%");
+		panel.add(button, "sizegroup buttons, aligny 0%");
 		
 		button = new JButton(actions.getEditAction());
 		panel.add(button, "sizegroup buttons");
 		
 		button = new JButton(actions.getNewStageAction());
-		panel.add(button,"sizegroup buttons");
+		panel.add(button, "sizegroup buttons");
 		
 		button = new JButton(actions.getDeleteAction());
 		button.setIcon(null);
 		button.setMnemonic(0);
-		panel.add(button,"sizegroup buttons");
-
+		panel.add(button, "sizegroup buttons");
+		
 		horizontal.setLeftComponent(panel);
-
+		
 
 		//  Upper-right segment, component addition buttons
-
-		panel = new JPanel(new MigLayout("fill, insets 0","[0::]"));
-
+		
+		panel = new JPanel(new MigLayout("fill, insets 0", "[0::]"));
+		
 		scroll = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
 				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
 		scroll.setViewportView(new ComponentAddButtons(document, componentSelectionModel,
 				scroll.getViewport()));
 		scroll.setBorder(null);
 		scroll.setViewportBorder(null);
-
+		
 		TitledBorder border = new TitledBorder("Add new component");
 		border.setTitleFont(border.getTitleFont().deriveFont(Font.BOLD));
 		scroll.setBorder(border);
-
-		panel.add(scroll,"grow");
-
+		
+		panel.add(scroll, "grow");
+		
 		horizontal.setRightComponent(panel);
-
+		
 		return horizontal;
 	}
 	
 	
-	
+
 	/**
 	 * Creates the menu for the window.
 	 */
@@ -389,7 +397,7 @@ public class BasicFrame extends JFrame {
 		menu.getAccessibleContext().setAccessibleDescription("File-handling related tasks");
 		menubar.add(menu);
 		
-		item = new JMenuItem("New",KeyEvent.VK_N);
+		item = new JMenuItem("New", KeyEvent.VK_N);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
 		item.setMnemonic(KeyEvent.VK_N);
 		item.getAccessibleContext().setAccessibleDescription("Create a new rocket design");
@@ -403,7 +411,7 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		item = new JMenuItem("Open...",KeyEvent.VK_O);
+		item = new JMenuItem("Open...", KeyEvent.VK_O);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
 		item.getAccessibleContext().setAccessibleDescription("Open a rocket design");
 		item.setIcon(Icons.FILE_OPEN);
@@ -416,14 +424,14 @@ public class BasicFrame extends JFrame {
 		
 		item = new JMenuItem("Open example...");
 		item.getAccessibleContext().setAccessibleDescription("Open an example rocket design");
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
 				ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
 		item.setIcon(Icons.FILE_OPEN_EXAMPLE);
 		item.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent e) {
 				URL[] urls = ExampleDesignDialog.selectExampleDesigns(BasicFrame.this);
 				if (urls != null) {
-					for (URL u: urls) {
+					for (URL u : urls) {
 						open(u, BasicFrame.this);
 					}
 				}
@@ -433,7 +441,7 @@ public class BasicFrame extends JFrame {
 		
 		menu.addSeparator();
 		
-		item = new JMenuItem("Save",KeyEvent.VK_S);
+		item = new JMenuItem("Save", KeyEvent.VK_S);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
 		item.getAccessibleContext().setAccessibleDescription("Save the current rocket design");
 		item.setIcon(Icons.FILE_SAVE);
@@ -444,10 +452,10 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		item = new JMenuItem("Save as...",KeyEvent.VK_A);
-		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, 
+		item = new JMenuItem("Save as...", KeyEvent.VK_A);
+		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
 				ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
-		item.getAccessibleContext().setAccessibleDescription("Save the current rocket design "+
+		item.getAccessibleContext().setAccessibleDescription("Save the current rocket design " +
 				"to a new file");
 		item.setIcon(Icons.FILE_SAVE_AS);
 		item.addActionListener(new ActionListener() {
@@ -457,10 +465,10 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-//		menu.addSeparator();
+		//		menu.addSeparator();
 		menu.add(new JSeparator());
 		
-		item = new JMenuItem("Close",KeyEvent.VK_C);
+		item = new JMenuItem("Close", KeyEvent.VK_C);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK));
 		item.getAccessibleContext().setAccessibleDescription("Close the current rocket design");
 		item.setIcon(Icons.FILE_CLOSE);
@@ -472,8 +480,8 @@ public class BasicFrame extends JFrame {
 		menu.add(item);
 		
 		menu.addSeparator();
-
-		item = new JMenuItem("Quit",KeyEvent.VK_Q);
+		
+		item = new JMenuItem("Quit", KeyEvent.VK_Q);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
 		item.getAccessibleContext().setAccessibleDescription("Quit the program");
 		item.setIcon(Icons.FILE_QUIT);
@@ -484,7 +492,7 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		
+
 
 		////  Edit
 		menu = new JMenu("Edit");
@@ -492,15 +500,15 @@ public class BasicFrame extends JFrame {
 		menu.getAccessibleContext().setAccessibleDescription("Rocket editing");
 		menubar.add(menu);
 		
-		
+
 		Action action = document.getUndoAction();
 		item = new JMenuItem(action);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));
 		item.setMnemonic(KeyEvent.VK_U);
 		item.getAccessibleContext().setAccessibleDescription("Undo the previous operation");
-
+		
 		menu.add(item);
-
+		
 		action = document.getRedoAction();
 		item = new JMenuItem(action);
 		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
@@ -511,13 +519,13 @@ public class BasicFrame extends JFrame {
 		
 		menu.addSeparator();
 		
-		
+
 		item = new JMenuItem(actions.getCutAction());
 		menu.add(item);
-	
+		
 		item = new JMenuItem(actions.getCopyAction());
 		menu.add(item);
-	
+		
 		item = new JMenuItem(actions.getPasteAction());
 		menu.add(item);
 		
@@ -528,7 +536,7 @@ public class BasicFrame extends JFrame {
 		
 		item = new JMenuItem("Preferences");
 		item.setIcon(Icons.PREFERENCES);
-		item.getAccessibleContext().setAccessibleDescription("Setup the application "+
+		item.getAccessibleContext().setAccessibleDescription("Setup the application " +
 				"preferences");
 		item.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent e) {
@@ -536,17 +544,17 @@ public class BasicFrame extends JFrame {
 			}
 		});
 		menu.add(item);
-	
 		
 
 
+
 		////  Analyze
 		menu = new JMenu("Analyze");
 		menu.setMnemonic(KeyEvent.VK_A);
 		menu.getAccessibleContext().setAccessibleDescription("Analyzing the rocket");
 		menubar.add(menu);
 		
-		item = new JMenuItem("Component analysis",KeyEvent.VK_C);
+		item = new JMenuItem("Component analysis", KeyEvent.VK_C);
 		item.getAccessibleContext().setAccessibleDescription("Analyze the rocket components " +
 				"separately");
 		item.addActionListener(new ActionListener() {
@@ -556,15 +564,15 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		
+
 		////  Debug
 		// (shown if openrocket.debug.menu is defined)
 		if (System.getProperty("openrocket.debug.menu") != null) {
 			menubar.add(makeDebugMenu());
 		}
+		
+
 
-		
-		
 		////  Help
 		
 		menu = new JMenu("Help");
@@ -572,9 +580,9 @@ public class BasicFrame extends JFrame {
 		menu.getAccessibleContext().setAccessibleDescription("Information about OpenRocket");
 		menubar.add(menu);
 		
-		
-		
-		item = new JMenuItem("License",KeyEvent.VK_L);
+
+
+		item = new JMenuItem("License", KeyEvent.VK_L);
 		item.getAccessibleContext().setAccessibleDescription("OpenRocket license information");
 		item.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent e) {
@@ -583,18 +591,18 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		item = new JMenuItem("Bug report",KeyEvent.VK_B);
+		item = new JMenuItem("Bug report", KeyEvent.VK_B);
 		item.getAccessibleContext().setAccessibleDescription("Information about reporting " +
 				"bugs in OpenRocket");
 		item.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent e) {
-//				new BugDialog(BasicFrame.this).setVisible(true);
+				//				new BugDialog(BasicFrame.this).setVisible(true);
 				BugReportDialog.showBugReportDialog(BasicFrame.this);
 			}
 		});
 		menu.add(item);
 		
-		item = new JMenuItem("About",KeyEvent.VK_A);
+		item = new JMenuItem("About", KeyEvent.VK_A);
 		item.getAccessibleContext().setAccessibleDescription("About OpenRocket");
 		item.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent e) {
@@ -603,7 +611,7 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		
+
 		this.setJMenuBar(menubar);
 	}
 	
@@ -621,11 +629,11 @@ public class BasicFrame extends JFrame {
 			public void actionPerformed(ActionEvent e) {
 				JOptionPane.showMessageDialog(BasicFrame.this,
 						new Object[] {
-						"The 'Debug' menu includes actions for testing and debugging " +
-						"OpenRocket.", " ",
-						"The menu is made visible by defining the system property " +
-						"'openrocket.debug.menu' when starting OpenRocket.",
-						"It should not be visible by default." },
+								"The 'Debug' menu includes actions for testing and debugging " +
+										"OpenRocket.", " ",
+								"The menu is made visible by defining the system property " +
+										"'openrocket.debug.menu' when starting OpenRocket.",
+								"It should not be visible by default." },
 						"Debug menu", JOptionPane.INFORMATION_MESSAGE);
 			}
 		});
@@ -641,9 +649,9 @@ public class BasicFrame extends JFrame {
 				int sel = JOptionPane.showOptionDialog(BasicFrame.this, new Object[] {
 						"Input text key to generate random rocket:",
 						field
-					}, "Generate random test rocket", JOptionPane.DEFAULT_OPTION, 
-					JOptionPane.QUESTION_MESSAGE, null, new Object[] {
-						"Random", "OK"
+					}, "Generate random test rocket", JOptionPane.DEFAULT_OPTION,
+						JOptionPane.QUESTION_MESSAGE, null, new Object[] {
+								"Random", "OK"
 				}, "OK");
 				
 				Rocket r;
@@ -663,7 +671,7 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		
+
 
 		item = new JMenuItem("Create 'Iso-Haisu'");
 		item.addActionListener(new ActionListener() {
@@ -692,8 +700,8 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		
-		
+
+
 		menu.addSeparator();
 		
 		item = new JMenuItem("Exception here");
@@ -732,13 +740,13 @@ public class BasicFrame extends JFrame {
 		});
 		menu.add(item);
 		
-		
-		
+
+
 		return menu;
 	}
 	
 	
-	
+
 	/**
 	 * Select the tab on the main pane.
 	 * 
@@ -747,42 +755,42 @@ public class BasicFrame extends JFrame {
 	public void selectTab(int tab) {
 		tabbedPane.setSelectedIndex(tab);
 	}
+	
+	
 
-	
-	
 	private void openAction() {
-	    JFileChooser chooser = new JFileChooser();
-	    
-	    chooser.addChoosableFileFilter(ALL_DESIGNS_FILTER);
-	    chooser.addChoosableFileFilter(OPENROCKET_DESIGN_FILTER);
-	    chooser.addChoosableFileFilter(ROCKSIM_DESIGN_FILTER);
-	    chooser.setFileFilter(ALL_DESIGNS_FILTER);
-
-	    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-	    chooser.setMultiSelectionEnabled(true);
-	    chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
-	    if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
-	    	return;
-	    
-	    Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
-
-	    File[] files = chooser.getSelectedFiles();
-	    
-	    for (File file: files) {
-	    	System.out.println("Opening file: " + file);
-	    	if (open(file, this)) {
-	    		
-	    		// Close previous window if replacing
-	    		if (replaceable && document.isSaved()) {
-	    			closeAction();
-	    			replaceable = false;
-	    		}
-	    	}
-	    }
+		JFileChooser chooser = new JFileChooser();
+		
+		chooser.addChoosableFileFilter(ALL_DESIGNS_FILTER);
+		chooser.addChoosableFileFilter(OPENROCKET_DESIGN_FILTER);
+		chooser.addChoosableFileFilter(ROCKSIM_DESIGN_FILTER);
+		chooser.setFileFilter(ALL_DESIGNS_FILTER);
+		
+		chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+		chooser.setMultiSelectionEnabled(true);
+		chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
+		if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
+			return;
+		
+		Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
+		
+		File[] files = chooser.getSelectedFiles();
+		
+		for (File file : files) {
+			System.out.println("Opening file: " + file);
+			if (open(file, this)) {
+				
+				// Close previous window if replacing
+				if (replaceable && document.isSaved()) {
+					closeAction();
+					replaceable = false;
+				}
+			}
+		}
 	}
 	
 	
-	
+
 	private static boolean open(URL url, BasicFrame parent) {
 		String filename = null;
 		
@@ -790,13 +798,15 @@ public class BasicFrame extends JFrame {
 		try {
 			URI uri = url.toURI();
 			filename = uri.getPath();
-		} catch (URISyntaxException ignore) { }
-
+		} catch (URISyntaxException ignore) {
+		}
+		
 		// Try URL-decoding the URL
 		if (filename == null) {
 			try {
 				filename = URLDecoder.decode(url.toString(), "UTF-8");
-			} catch (UnsupportedEncodingException ignore) { }
+			} catch (UnsupportedEncodingException ignore) {
+			}
 		}
 		
 		// Last resort
@@ -806,20 +816,20 @@ public class BasicFrame extends JFrame {
 		
 		// Remove path from filename
 		if (filename.lastIndexOf('/') >= 0) {
-			filename = filename.substring(filename.lastIndexOf('/')+1);
+			filename = filename.substring(filename.lastIndexOf('/') + 1);
 		}
 		
 		try {
 			InputStream is = url.openStream();
 			if (open(is, filename, parent)) {
-	    		// Close previous window if replacing
-	    		if (parent.replaceable && parent.document.isSaved()) {
-	    			parent.closeAction();
-	    			parent.replaceable = false;
-	    		}
+				// Close previous window if replacing
+				if (parent.replaceable && parent.document.isSaved()) {
+					parent.closeAction();
+					parent.replaceable = false;
+				}
 			}
 		} catch (IOException e) {
-			JOptionPane.showMessageDialog(parent, 
+			JOptionPane.showMessageDialog(parent,
 					"An error occurred while opening the file " + filename,
 					"Error loading file", JOptionPane.ERROR_MESSAGE);
 		}
@@ -842,7 +852,7 @@ public class BasicFrame extends JFrame {
 		return open(worker, filename, null, parent);
 	}
 	
-
+	
 	/**
 	 * Open the specified file in a new design frame.  If an error occurs, an error
 	 * dialog is shown and <code>false</code> is returned.
@@ -856,7 +866,7 @@ public class BasicFrame extends JFrame {
 		return open(worker, file.getName(), file, parent);
 	}
 	
-
+	
 	/**
 	 * Open the specified file using the provided worker.
 	 * 
@@ -866,49 +876,51 @@ public class BasicFrame extends JFrame {
 	 * @param parent
 	 * @return
 	 */
-	private static boolean open(OpenFileWorker worker, String filename, File file, 
+	private static boolean open(OpenFileWorker worker, String filename, File file,
 			Window parent) {
-
+		
+		MotorDatabaseLoadingDialog.check(null);
+		
 		// Open the file in a Swing worker thread
-		if (!SwingWorkerDialog.runWorker(parent, "Opening file", 
+		if (!SwingWorkerDialog.runWorker(parent, "Opening file",
 				"Reading " + filename + "...", worker)) {
-
+			
 			// User cancelled the operation
 			return false;
 		}
-
 		
+
 		// Handle the document
 		OpenRocketDocument doc = null;
 		try {
-
+			
 			doc = worker.get();
-
+			
 		} catch (ExecutionException e) {
-
+			
 			Throwable cause = e.getCause();
-
+			
 			if (cause instanceof FileNotFoundException) {
-
-				JOptionPane.showMessageDialog(parent, 
+				
+				JOptionPane.showMessageDialog(parent,
 						"File not found: " + filename,
 						"Error opening file", JOptionPane.ERROR_MESSAGE);
 				return false;
-
+				
 			} else if (cause instanceof RocketLoadException) {
-
-				JOptionPane.showMessageDialog(parent, 
-						"Unable to open file '" + filename +"': " 
-						+ cause.getMessage(),
+				
+				JOptionPane.showMessageDialog(parent,
+						"Unable to open file '" + filename + "': "
+								+ cause.getMessage(),
 						"Error opening file", JOptionPane.ERROR_MESSAGE);
 				return false;
-
+				
 			} else {
-
+				
 				throw new BugException("Unknown error when opening file", e);
-
+				
 			}
-
+			
 		} catch (InterruptedException e) {
 			throw new BugException("EDT was interrupted", e);
 		}
@@ -917,59 +929,55 @@ public class BasicFrame extends JFrame {
 			throw new BugException("BUG: Document loader returned null");
 		}
 		
-		
-	    // Show warnings
+
+		// Show warnings
 		WarningSet warnings = worker.getRocketLoader().getWarnings();
 		if (!warnings.isEmpty()) {
 			WarningDialog.showWarnings(parent,
 					new Object[] {
-					"The following problems were encountered while opening " + filename + ".",
-					"Some design features may not have been loaded correctly."
+							"The following problems were encountered while opening " + filename + ".",
+							"Some design features may not have been loaded correctly."
 					},
 					"Warnings while opening file", warnings);
 		}
 		
-	    
-	    // Set document state
-	    doc.setFile(file);
-	    doc.setSaved(true);
 
-	    // Open the frame
-	    BasicFrame frame = new BasicFrame(doc);
-	    frame.setVisible(true);
-
-	    return true;
+		// Set document state
+		doc.setFile(file);
+		doc.setSaved(true);
+		
+		// Open the frame
+		BasicFrame frame = new BasicFrame(doc);
+		frame.setVisible(true);
+		
+		return true;
 	}
 	
 	
-	
-	
-	
-	
-	
-	
-	
+
+
+
 	private boolean saveAction() {
 		File file = document.getFile();
-		if (file==null) {
+		if (file == null) {
 			return saveAsAction();
 		}
 		
 		// Saving RockSim designs is not supported
 		if (ROCKSIM_DESIGN_FILTER.accept(file)) {
-			file = new File(file.getAbsolutePath().replaceAll(".[rR][kK][tT](.[gG][zZ])?$", 
+			file = new File(file.getAbsolutePath().replaceAll(".[rR][kK][tT](.[gG][zZ])?$",
 					".ork"));
-
+			
 			int option = JOptionPane.showConfirmDialog(this, new Object[] {
 					"Saving designs in RockSim format is not supported.",
-					"Save in OpenRocket format instead ("+file.getName()+")?"
-				}, "Save "+file.getName(), JOptionPane.YES_NO_OPTION, 
-				JOptionPane.QUESTION_MESSAGE, null);
+					"Save in OpenRocket format instead (" + file.getName() + ")?"
+				}, "Save " + file.getName(), JOptionPane.YES_NO_OPTION,
+					JOptionPane.QUESTION_MESSAGE, null);
 			if (option != JOptionPane.YES_OPTION)
 				return false;
 			
 			document.setFile(file);
-        }
+		}
 		return saveAs(file);
 	}
 	
@@ -978,8 +986,8 @@ public class BasicFrame extends JFrame {
 		File file = null;
 		while (file == null) {
 			// TODO: HIGH: what if *.rkt chosen?
-			StorageOptionChooser storageChooser = 
-				new StorageOptionChooser(document, document.getDefaultStorageOptions());
+			StorageOptionChooser storageChooser =
+					new StorageOptionChooser(document, document.getDefaultStorageOptions());
 			JFileChooser chooser = new JFileChooser();
 			chooser.setFileFilter(OPENROCKET_DESIGN_FILTER);
 			chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
@@ -993,7 +1001,7 @@ public class BasicFrame extends JFrame {
 			file = chooser.getSelectedFile();
 			if (file == null)
 				return false;
-
+			
 			Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
 			storageChooser.storeOptions(document.getDefaultStorageOptions());
 			
@@ -1004,53 +1012,53 @@ public class BasicFrame extends JFrame {
 			}
 			
 			if (file.exists()) {
-				int result = JOptionPane.showConfirmDialog(this, 
-						"File '"+file.getName()+"' exists.  Do you want to overwrite it?", 
+				int result = JOptionPane.showConfirmDialog(this,
+						"File '" + file.getName() + "' exists.  Do you want to overwrite it?",
 						"File exists", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
 				if (result != JOptionPane.YES_OPTION)
 					return false;
 			}
 		}
-	    saveAs(file);
-	    return true;
+		saveAs(file);
+		return true;
 	}
 	
 	
 	private boolean saveAs(File file) {
-	    System.out.println("Saving to file: " + file.getName());
-	    boolean saved = false;
-	    
-	    if (!StorageOptionChooser.verifyStorageOptions(document, this)) {
-	    	// User cancelled the dialog
-	    	return false;
-	    }
+		System.out.println("Saving to file: " + file.getName());
+		boolean saved = false;
+		
+		if (!StorageOptionChooser.verifyStorageOptions(document, this)) {
+			// User cancelled the dialog
+			return false;
+		}
+		
 
-
-	    SaveFileWorker worker = new SaveFileWorker(document, file, ROCKET_SAVER);
-
-	    if (!SwingWorkerDialog.runWorker(this, "Saving file", 
-	    		"Writing " + file.getName() + "...", worker)) {
-	    	
-	    	// User cancelled the save
-	    	file.delete();
-	    	return false;
-	    }
-	    
-	    try {
+		SaveFileWorker worker = new SaveFileWorker(document, file, ROCKET_SAVER);
+		
+		if (!SwingWorkerDialog.runWorker(this, "Saving file",
+				"Writing " + file.getName() + "...", worker)) {
+			
+			// User cancelled the save
+			file.delete();
+			return false;
+		}
+		
+		try {
 			worker.get();
 			document.setFile(file);
 			document.setSaved(true);
 			saved = true;
-		    setTitle();
+			setTitle();
 		} catch (ExecutionException e) {
-
+			
 			Throwable cause = e.getCause();
 			
 			if (cause instanceof IOException) {
-		    	JOptionPane.showMessageDialog(this, new String[] { 
-		    			"An I/O error occurred while saving:",
-		    			e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
-		    	return false;
+				JOptionPane.showMessageDialog(this, new String[] {
+						"An I/O error occurred while saving:",
+						e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
+				return false;
 			} else {
 				Reflection.handleWrappedException(e);
 			}
@@ -1058,23 +1066,23 @@ public class BasicFrame extends JFrame {
 		} catch (InterruptedException e) {
 			throw new BugException("EDT was interrupted", e);
 		}
-	    
-	    return saved;
+		
+		return saved;
 	}
 	
 	
 	private boolean closeAction() {
 		if (!document.isSaved()) {
 			ComponentConfigDialog.hideDialog();
-			int result = JOptionPane.showConfirmDialog(this, 
-					"Design '"+rocket.getName()+"' has not been saved.  " +
-							"Do you want to save it?", 
-					"Design not saved", JOptionPane.YES_NO_CANCEL_OPTION, 
+			int result = JOptionPane.showConfirmDialog(this,
+					"Design '" + rocket.getName() + "' has not been saved.  " +
+							"Do you want to save it?",
+					"Design not saved", JOptionPane.YES_NO_CANCEL_OPTION,
 					JOptionPane.QUESTION_MESSAGE);
 			if (result == JOptionPane.YES_OPTION) {
 				// Save
 				if (!saveAction())
-					return false;  // If save was interrupted
+					return false; // If save was interrupted
 			} else if (result == JOptionPane.NO_OPTION) {
 				// Don't save: No-op
 			} else {
@@ -1085,7 +1093,7 @@ public class BasicFrame extends JFrame {
 		
 		// Rocket has been saved or discarded
 		this.dispose();
-
+		
 		// TODO: LOW: Close only dialogs that have this frame as their parent
 		ComponentConfigDialog.hideDialog();
 		ComponentAnalysisDialog.hideDialog();
@@ -1110,6 +1118,7 @@ public class BasicFrame extends JFrame {
 	 * Open a new design window with a basic rocket+stage.
 	 */
 	public static void newAction() {
+		log.debug("New action initiated");
 		Rocket rocket = new Rocket();
 		Stage stage = new Stage();
 		stage.setName("Sustainer");
@@ -1127,7 +1136,7 @@ public class BasicFrame extends JFrame {
 	 * Quit the application.  Confirms saving unsaved designs.  The action of File->Quit.
 	 */
 	public static void quitAction() {
-		for (int i=frames.size()-1; i>=0; i--) {
+		for (int i = frames.size() - 1; i >= 0; i--) {
 			if (!frames.get(i).closeAction()) {
 				// Close canceled
 				return;
@@ -1148,8 +1157,8 @@ public class BasicFrame extends JFrame {
 		String title;
 		
 		title = rocket.getName();
-		if (file!=null) {
-			title = title + " ("+file.getName()+")";
+		if (file != null) {
+			title = title + " (" + file.getName() + ")";
 		}
 		if (!saved)
 			title = "*" + title;
@@ -1158,7 +1167,7 @@ public class BasicFrame extends JFrame {
 	}
 	
 	
-	
+
 	/**
 	 * Find a currently open BasicFrame containing the specified rocket.  This method
 	 * can be used to map a Rocket to a BasicFrame from GUI methods.
@@ -1167,7 +1176,7 @@ public class BasicFrame extends JFrame {
 	 * @return		 the corresponding BasicFrame, or <code>null</code> if none found.
 	 */
 	public static BasicFrame findFrame(Rocket rocket) {
-		for (BasicFrame f: frames) {
+		for (BasicFrame f : frames) {
 			if (f.rocket == rocket)
 				return f;
 		}
@@ -1182,7 +1191,7 @@ public class BasicFrame extends JFrame {
 	 * @return		 the corresponding OpenRocketDocument, or <code>null</code> if not found.
 	 */
 	public static OpenRocketDocument findDocument(Rocket rocket) {
-		for (BasicFrame f: frames) {
+		for (BasicFrame f : frames) {
 			if (f.rocket == rocket)
 				return f.document;
 		}
@@ -1214,7 +1223,7 @@ public class BasicFrame extends JFrame {
 		// Initialize the splash screen with version info
 		Splash.init();
 		
-		
+
 		// Start update info fetching
 		final UpdateInfoRetriever updateInfo;
 		if (Prefs.getCheckUpdates()) {
@@ -1224,18 +1233,18 @@ public class BasicFrame extends JFrame {
 			updateInfo = null;
 		}
 		
-		
+
 		// Set the best available look-and-feel
 		GUIUtil.setBestLAF();
-
+		
 		// Set tooltip delay time.  Tooltips are used in MotorChooserDialog extensively.
 		ToolTipManager.sharedInstance().setDismissDelay(30000);
 		
-		
+
 		// Setup the uncaught exception handler
 		ExceptionHandler.registerExceptionHandler();
 		
-		
+
 		// Load defaults
 		Prefs.loadDefaultUnits();
 		
@@ -1248,7 +1257,7 @@ public class BasicFrame extends JFrame {
 			newAction();
 		}
 		
-		
+
 		// Check whether update info has been fetched or whether it needs more time
 		checkUpdateStatus(updateInfo);
 	}
@@ -1257,15 +1266,16 @@ public class BasicFrame extends JFrame {
 	private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
 		if (updateInfo == null)
 			return;
-
+		
 		int delay = 1000;
 		if (!updateInfo.isRunning())
 			delay = 100;
-
+		
 		final Timer timer = new Timer(delay, null);
-
+		
 		ActionListener listener = new ActionListener() {
 			private int count = 5;
+			
 			@Override
 			public void actionPerformed(ActionEvent e) {
 				if (!updateInfo.isRunning()) {
@@ -1273,7 +1283,7 @@ public class BasicFrame extends JFrame {
 					
 					String current = Prefs.getVersion();
 					String last = Prefs.getString(Prefs.LAST_UPDATE, "");
-
+					
 					UpdateInfo info = updateInfo.getUpdateInfo();
 					if (info != null && info.getLatestVersion() != null &&
 							!current.equals(info.getLatestVersion()) &&
@@ -1311,12 +1321,12 @@ public class BasicFrame extends JFrame {
 		
 		// Check command-line for files
 		boolean opened = false;
-		for (String file: args) {
+		for (String file : args) {
 			if (open(new File(file), null)) {
 				opened = true;
 			}
 		}
 		return opened;
 	}
-
+	
 }
diff --git a/src/net/sf/openrocket/gui/plot/PlotDialog.java b/src/net/sf/openrocket/gui/plot/PlotDialog.java
index ad6e34a58..77d5338e3 100644
--- a/src/net/sf/openrocket/gui/plot/PlotDialog.java
+++ b/src/net/sf/openrocket/gui/plot/PlotDialog.java
@@ -1,6 +1,7 @@
 package net.sf.openrocket.gui.plot;
 
 import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Composite;
 import java.awt.Font;
@@ -62,6 +63,8 @@ import org.jfree.ui.TextAnchor;
 
 public class PlotDialog extends JDialog {
 	
+	private static final float PLOT_STROKE_WIDTH = 1.5f;
+	
 	private static final Color DEFAULT_EVENT_COLOR = new Color(0, 0, 0);
 	private static final Map<FlightEvent.Type, Color> EVENT_COLORS =
 			new HashMap<FlightEvent.Type, Color>();
@@ -221,6 +224,9 @@ public class PlotDialog extends JDialog {
 				ModifiedXYItemRenderer r = new ModifiedXYItemRenderer();
 				r.setBaseShapesVisible(initialShowPoints);
 				r.setBaseShapesFilled(true);
+				for (int j = 0; j < data[i].getSeriesCount(); j++) {
+					r.setSeriesStroke(j, new BasicStroke(PLOT_STROKE_WIDTH));
+				}
 				renderers.add(r);
 				plot.setRenderer(axisno, r);
 				plot.mapDatasetToRangeAxis(axisno, axisno);
diff --git a/src/net/sf/openrocket/motor/ThrustCurveMotor.java b/src/net/sf/openrocket/motor/ThrustCurveMotor.java
index 10a97deb1..ce3108dd0 100644
--- a/src/net/sf/openrocket/motor/ThrustCurveMotor.java
+++ b/src/net/sf/openrocket/motor/ThrustCurveMotor.java
@@ -4,7 +4,9 @@ import java.text.Collator;
 import java.util.Arrays;
 import java.util.Locale;
 
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.Inertia;
@@ -12,6 +14,7 @@ import net.sf.openrocket.util.MathUtil;
 
 
 public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
+	private static final LogHelper log = Application.getLogger();
 	
 	public static final double MAX_THRUST = 10e6;
 	
@@ -171,7 +174,12 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
 	}
 	
 	
-
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * NOTE: In most cases you want to examine the motor type of the ThrustCurveMotorSet,
+	 * not the ThrustCurveMotor itself.
+	 */
 	@Override
 	public Type getMotorType() {
 		return type;
@@ -391,6 +399,7 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
 		private int modID = 0;
 		
 		public ThrustCurveMotorInstance() {
+			log.debug("ThrustCurveMotor:  Creating motor instance of " + ThrustCurveMotor.this);
 			position = 0;
 			prevTime = 0;
 			instThrust = 0;
@@ -434,22 +443,18 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
 		@Override
 		public void step(double nextTime, double acceleration, AtmosphericConditions cond) {
 			
-			System.out.println("MOTOR: Stepping instance " + this + " to time " + nextTime);
-			
 			if (!(nextTime >= prevTime)) {
 				// Also catches NaN
 				throw new IllegalArgumentException("Stepping backwards in time, current=" +
 						prevTime + " new=" + nextTime);
 			}
 			if (MathUtil.equals(prevTime, nextTime)) {
-				System.out.println("Same time as earlier");
 				return;
 			}
 			
 			modID++;
 			
 			if (position >= time.length - 1) {
-				System.out.println("Thrust has ended");
 				// Thrust has ended
 				prevTime = nextTime;
 				stepThrust = 0;
@@ -501,19 +506,10 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
 			if (position < time.length - 1) {
 				nextCG = MathUtil.map(nextTime, time[position], time[position + 1],
 						cg[position], cg[position + 1]);
-				
-				System.out.println("nextTime=" + nextTime +
-						" time[position]=" + time[position] +
-						" time[position+1]=" + time[position + 1] +
-						" mass[position]=" + cg[position].weight * 1000 +
-						" mass[position+1]=" + cg[position + 1].weight * 1000 +
-						" result=" + nextCG.weight * 1000 +
-						" position=" + position);
 			} else {
 				nextCG = cg[cg.length - 1];
 			}
 			stepCG = instCG.add(nextCG).multiply(0.5);
-			System.out.println("instMass=" + instCG.weight + " nextMass=" + nextCG.weight + " stepMass=" + stepCG.weight);
 			instCG = nextCG;
 			
 			// Update time
diff --git a/src/net/sf/openrocket/simulation/RK4SimulationStepper.java b/src/net/sf/openrocket/simulation/RK4SimulationStepper.java
index 85add4865..45be122db 100644
--- a/src/net/sf/openrocket/simulation/RK4SimulationStepper.java
+++ b/src/net/sf/openrocket/simulation/RK4SimulationStepper.java
@@ -412,14 +412,12 @@ public class RK4SimulationStepper extends AbstractSimulationStepper {
 		if (status.getSimulationTime() < status.getStartWarningTime())
 			warnings = null;
 		
-		System.out.println("flightConditions=" + store.flightConditions);
-		
+
 		// Calculate aerodynamic forces
 		store.forces = status.getSimulationConditions().getAerodynamicCalculator()
 				.getAerodynamicForces(status.getConfiguration(), store.flightConditions, warnings);
 		
-		System.out.println("CP=" + store.forces.getCP());
-		
+
 		// Add very small randomization to yaw & pitch moments to prevent over-perfect flight
 		// TODO: HIGH: This should rather be performed as a listener
 		store.forces.setCm(store.forces.getCm() + (PITCH_YAW_RANDOM * 2 * (random.nextDouble() - 0.5)));
diff --git a/src/net/sf/openrocket/startup/Application.java b/src/net/sf/openrocket/startup/Application.java
index ec5172145..a00c9535d 100644
--- a/src/net/sf/openrocket/startup/Application.java
+++ b/src/net/sf/openrocket/startup/Application.java
@@ -1,6 +1,6 @@
 package net.sf.openrocket.startup;
 
-import net.sf.openrocket.database.MotorSetDatabase;
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.logging.LogLevel;
 import net.sf.openrocket.logging.LogLevelBufferLogger;
@@ -16,7 +16,7 @@ public final class Application {
 	private static LogHelper logger;
 	private static LogLevelBufferLogger logBuffer;
 	
-	private static MotorSetDatabase motorSetDatabase;
+	private static ThrustCurveMotorSetDatabase motorSetDatabase;
 	
 	// Initialize the logger to something sane for testing without executing Startup
 	static {
@@ -68,14 +68,14 @@ public final class Application {
 	/**
 	 * Return the database of all thrust curves loaded into the system.
 	 */
-	public static MotorSetDatabase getMotorSetDatabase() {
+	public static ThrustCurveMotorSetDatabase getMotorSetDatabase() {
 		return motorSetDatabase;
 	}
 	
 	/**
 	 * Set the database of thrust curves loaded into the system.
 	 */
-	public static void setMotorSetDatabase(MotorSetDatabase motorSetDatabase) {
+	public static void setMotorSetDatabase(ThrustCurveMotorSetDatabase motorSetDatabase) {
 		Application.motorSetDatabase = motorSetDatabase;
 	}
 	
diff --git a/src/net/sf/openrocket/startup/Startup.java b/src/net/sf/openrocket/startup/Startup.java
index d8ff127f1..971a5e94c 100644
--- a/src/net/sf/openrocket/startup/Startup.java
+++ b/src/net/sf/openrocket/startup/Startup.java
@@ -8,6 +8,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.swing.JOptionPane;
 import javax.swing.SwingUtilities;
@@ -17,7 +18,8 @@ import javax.swing.ToolTipManager;
 import net.sf.openrocket.communication.UpdateInfo;
 import net.sf.openrocket.communication.UpdateInfoRetriever;
 import net.sf.openrocket.database.Databases;
-import net.sf.openrocket.database.MotorSetDatabase;
+import net.sf.openrocket.database.ThrustCurveMotorSet;
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
 import net.sf.openrocket.file.DirectoryIterator;
 import net.sf.openrocket.file.GeneralMotorLoader;
 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
@@ -55,9 +57,11 @@ public class Startup {
 	
 	private static final String THRUSTCURVE_DIRECTORY = "datafiles/thrustcurves/";
 	
+
+	/** Block motor loading for this many milliseconds */
+	private static AtomicInteger blockLoading = new AtomicInteger(Integer.MAX_VALUE);
+	
 	
-
-
 	public static void main(final String[] args) throws Exception {
 		
 		// Initialize logging first so we can use it
@@ -67,10 +71,12 @@ public class Startup {
 		checkHead();
 		
 		// Check that we're running a good version of a JRE
+		log.info("Checking JRE compatibility");
 		VersionHelper.checkVersion();
 		VersionHelper.checkOpenJDK();
 		
 		// Run the actual startup method in the EDT since it can use progress dialogs etc.
+		log.info("Running main");
 		SwingUtilities.invokeAndWait(new Runnable() {
 			@Override
 			public void run() {
@@ -78,6 +84,10 @@ public class Startup {
 			}
 		});
 		
+		log.info("Startup complete");
+		
+		// Block motor loading for 2 seconds to allow window painting
+		blockLoading.set(2000);
 	}
 	
 	
@@ -86,21 +96,26 @@ public class Startup {
 	private static void runMain(String[] args) {
 		
 		// Initialize the splash screen with version info
+		log.info("Initializing the splash screen");
 		Splash.init();
 		
 		// Setup the uncaught exception handler
+		log.info("Registering exception handler");
 		ExceptionHandler.registerExceptionHandler();
 		
 		// Start update info fetching
 		final UpdateInfoRetriever updateInfo;
 		if (Prefs.getCheckUpdates()) {
+			log.info("Starting update check");
 			updateInfo = new UpdateInfoRetriever();
 			updateInfo.start();
 		} else {
+			log.info("Update check disabled");
 			updateInfo = null;
 		}
 		
 		// Set the best available look-and-feel
+		log.info("Setting best LAF");
 		GUIUtil.setBestLAF();
 		
 		// Set tooltip delay time.  Tooltips are used in MotorChooserDialog extensively.
@@ -111,15 +126,18 @@ public class Startup {
 		
 		// Load motors etc.
 		// TODO: HIGH: Use new motor loading
-		//		loadMotor();
+		log.info("Loading databases");
+		loadMotor();
 		Databases.fakeMethod();
 		
 		// Starting action (load files or open new document)
+		log.info("Opening main application window");
 		if (!handleCommandLine(args)) {
 			BasicFrame.newAction();
 		}
 		
 		// Check whether update info has been fetched or whether it needs more time
+		log.info("Checking update status");
 		checkUpdateStatus(updateInfo);
 	}
 	
@@ -129,23 +147,48 @@ public class Startup {
 		
 		log.info("Starting motor loading from " + THRUSTCURVE_DIRECTORY +
 				" in background thread.");
-		MotorSetDatabase db = new MotorSetDatabase(true) {
+		ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(true) {
 			
 			@Override
 			protected void loadMotors() {
+				
+				log.info("Blocking motor loading while starting up");
+				
+				// Block for 100ms a time until timeout or database in use
+				while (!inUse && blockLoading.addAndGet(-100) > 0) {
+					try {
+						Thread.sleep(100);
+					} catch (InterruptedException e) {
+					}
+				}
+				
+				log.info("Blocking ended, inUse=" + inUse + " slowLoadingCount=" + blockLoading.get());
+				
+				log.info("Started to load motors from " + THRUSTCURVE_DIRECTORY);
+				long t0 = System.currentTimeMillis();
+				
+				int fileCount = 0;
+				int thrustCurveCount = 0;
+				int distinctMotorCount = 0;
+				int distinctThrustCurveCount = 0;
+				
 				GeneralMotorLoader loader = new GeneralMotorLoader();
-				DirectoryIterator iterator =
-						DirectoryIterator.findDirectory(THRUSTCURVE_DIRECTORY,
-								new SimpleFileFilter("", false, "eng", "rkt"));
+				DirectoryIterator iterator = DirectoryIterator.findDirectory(THRUSTCURVE_DIRECTORY,
+								new SimpleFileFilter("", false, "eng", "rse"));
 				if (iterator == null) {
-					throw new IllegalStateException("No thrust curves found, " +
-							"distribution built wrong");
+					throw new IllegalStateException("No thrust curves found, distribution built wrong");
 				}
 				while (iterator.hasNext()) {
 					final Pair<String, InputStream> input = iterator.next();
+					log.debug("Loading motors from file " + input.getU());
+					fileCount++;
 					try {
 						List<Motor> motors = loader.load(input.getV(), input.getU());
+						if (motors.size() == 0) {
+							log.warn("No motors found in file " + input.getU());
+						}
 						for (Motor m : motors) {
+							thrustCurveCount++;
 							this.addMotor((ThrustCurveMotor) m);
 						}
 					} catch (IOException e) {
@@ -157,7 +200,19 @@ public class Startup {
 							log.error("IOException when closing InputStream", e);
 						}
 					}
+					
 				}
+				
+				long t1 = System.currentTimeMillis();
+				
+				// Count statistics
+				distinctMotorCount = motorSets.size();
+				for (ThrustCurveMotorSet set : motorSets) {
+					distinctThrustCurveCount += set.getMotorCount();
+				}
+				log.info("Motor loading done, took " + (t1 - t0) + " ms to load "
+						+ fileCount + " files containing " + thrustCurveCount + " thrust curves which contained "
+						+ distinctMotorCount + " distinct motors with " + distinctThrustCurveCount + " thrust curves.");
 			}
 			
 		};
@@ -240,6 +295,8 @@ public class Startup {
 	 */
 	private static void checkHead() {
 		
+		log.info("Checking for graphics head");
+		
 		if (GraphicsEnvironment.isHeadless()) {
 			log.error("Application is headless.");
 			System.err.println();
diff --git a/src/net/sf/openrocket/startup/VersionHelper.java b/src/net/sf/openrocket/startup/VersionHelper.java
index 085638689..3d90d3e9d 100644
--- a/src/net/sf/openrocket/startup/VersionHelper.java
+++ b/src/net/sf/openrocket/startup/VersionHelper.java
@@ -4,73 +4,74 @@ import net.sf.openrocket.logging.LogHelper;
 
 public class VersionHelper {
 	
-	private static final LogHelper logger = Application.getLogger();
-
+	private static final LogHelper log = Application.getLogger();
+	
 	private static final int REQUIRED_MAJOR_VERSION = 1;
 	private static final int REQUIRED_MINOR_VERSION = 6;
 	
 	// OpenJDK 1.6.0_0-b16 is known to work, 1.6.0_0-b12 does not
 	private static final String BAD_OPENJDK_VERSION = "^1.6.0_0-b([0-9]|1[1-5])$";
-
-
+	
+	
 	/**
 	 * Check that the JRE version is high enough.
 	 */
 	static void checkVersion() {
+		
 		String[] version = System.getProperty("java.specification.version", "").split("\\.");
 		
 		String jreName = System.getProperty("java.vm.name", "(unknown)");
 		String jreVersion = System.getProperty("java.runtime.version", "(unknown)");
 		String jreVendor = System.getProperty("java.vendor", "(unknown)");
 		
-		logger.info("Running JRE " + jreName + " version " + jreVersion + " by " + jreVendor);
+		log.info("Running JRE " + jreName + " version " + jreVersion + " by " + jreVendor);
 		
 		int major, minor;
-	
+		
 		try {
 			major = Integer.parseInt(version[0]);
 			minor = Integer.parseInt(version[1]);
 			
-			if (major < REQUIRED_MAJOR_VERSION || 
+			if (major < REQUIRED_MAJOR_VERSION ||
 					(major == REQUIRED_MAJOR_VERSION && minor < REQUIRED_MINOR_VERSION)) {
-				Startup.error(new String[] {"Java SE version 6 is required to run OpenRocket.",
+				Startup.error(new String[] { "Java SE version 6 is required to run OpenRocket.",
 						"You are currently running " + jreName + " version " +
-						jreVersion + " by " + jreVendor});
+								jreVersion + " by " + jreVendor });
 			}
 			
 		} catch (RuntimeException e) {
 			
-			Startup.confirm(new String[] {"The Java version in use could not be detected.",
+			Startup.confirm(new String[] { "The Java version in use could not be detected.",
 					"OpenRocket requires at least Java SE 6.",
-					"Continue anyway?"});
+					"Continue anyway?" });
 			
 		}
 		
 	}
-
+	
 	/**
 	 * Check whether OpenJDK is being used, and if it is warn the user about
 	 * problems and confirm whether to continue.
 	 */
 	static void checkOpenJDK() {
 		
-		if (System.getProperty("java.runtime.name", "").toLowerCase().indexOf("icedtea")>=0 ||
-				System.getProperty("java.vm.name", "").toLowerCase().indexOf("openjdk")>=0) {
-	
+		if (System.getProperty("java.runtime.name", "").toLowerCase().indexOf("icedtea") >= 0 ||
+				System.getProperty("java.vm.name", "").toLowerCase().indexOf("openjdk") >= 0) {
+			
 			String jreName = System.getProperty("java.vm.name", "(unknown)");
 			String jreVersion = System.getProperty("java.runtime.version", "(unknown)");
 			String jreVendor = System.getProperty("java.vendor", "(unknown)");
-	
-			if (jreVersion.matches(BAD_OPENJDK_VERSION)) {
 			
-				Startup.confirm(new String[] {"Old versions of OpenJDK are known to have problems " +
+			if (jreVersion.matches(BAD_OPENJDK_VERSION)) {
+				
+				Startup.confirm(new String[] { "Old versions of OpenJDK are known to have problems " +
 						"running OpenRocket.",
 						" ",
 						"You are currently running " + jreName + " version " +
-						jreVersion + " by " + jreVendor,
-						"Do you want to continue?"});
+								jreVersion + " by " + jreVendor,
+						"Do you want to continue?" });
 			}
 		}
 	}
-
+	
 }
diff --git a/src/net/sf/openrocket/util/BugException.java b/src/net/sf/openrocket/util/BugException.java
index 94a283495..140862d0d 100644
--- a/src/net/sf/openrocket/util/BugException.java
+++ b/src/net/sf/openrocket/util/BugException.java
@@ -6,20 +6,17 @@ package net.sf.openrocket.util;
  * @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/GUIUtil.java b/src/net/sf/openrocket/util/GUIUtil.java
index 4f552b819..46b789310 100644
--- a/src/net/sf/openrocket/util/GUIUtil.java
+++ b/src/net/sf/openrocket/util/GUIUtil.java
@@ -2,6 +2,7 @@ package net.sf.openrocket.util;
 
 import java.awt.Component;
 import java.awt.Container;
+import java.awt.Font;
 import java.awt.Image;
 import java.awt.KeyboardFocusManager;
 import java.awt.Point;
@@ -96,8 +97,9 @@ public class GUIUtil {
 
 	/**
 	 * Set suitable options for a single-use disposable dialog.  This includes
-	 * setting ESC to close the dialog and adding the appropriate window icons.
-	 * If defaultButton is provided, it is set to the default button action.
+	 * setting ESC to close the dialog, adding the appropriate window icons and
+	 * setting the location based on the platform.  If defaultButton is provided, 
+	 * it is set to the default button action.
 	 * <p>
 	 * The default button must be already attached to the dialog.
 	 * 
@@ -108,6 +110,7 @@ public class GUIUtil {
 		installEscapeCloseOperation(dialog);
 		setWindowIcons(dialog);
 		addModelNullingListener(dialog);
+		dialog.setLocationByPlatform(true);
 		if (defaultButton != null) {
 			setDefaultButton(defaultButton);
 		}
@@ -238,6 +241,19 @@ public class GUIUtil {
 	}
 	
 	
+	/**
+	 * Changes the size of the font of the specified component by the given amount.
+	 * 
+	 * @param component		the component for which to change the font
+	 * @param size			the change in the font size
+	 */
+	public static void changeFontSize(JComponent component, float size) {
+		Font font = component.getFont();
+		font = font.deriveFont(font.getSize2D() + size);
+		component.setFont(font);
+	}
+	
+	
 	/**
 	 * Traverses recursively the component tree, and sets all applicable component 
 	 * models to null, so as to remove the listener connections.  After calling this
diff --git a/src/net/sf/openrocket/util/Icons.java b/src/net/sf/openrocket/util/Icons.java
index a447009f1..52153e148 100644
--- a/src/net/sf/openrocket/util/Icons.java
+++ b/src/net/sf/openrocket/util/Icons.java
@@ -10,10 +10,17 @@ import javax.swing.ImageIcon;
 
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.main.ExceptionHandler;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
 
 
 public class Icons {
-
+	private static final LogHelper log = Application.getLogger();
+	
+	static {
+		log.debug("Starting to load icons");
+	}
+	
 	/**
 	 * Icons used for showing the status of a simulation (up to date, out of date, etc).
 	 */
@@ -34,7 +41,7 @@ public class Icons {
 		SIMULATION_LISTENER_OK = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.UPTODATE);
 		SIMULATION_LISTENER_ERROR = SIMULATION_STATUS_ICON_MAP.get(Simulation.Status.OUTDATED);
 	}
-
+	
 
 	public static final Icon FILE_NEW = loadImageIcon("pix/icons/document-new.png", "New document");
 	public static final Icon FILE_OPEN = loadImageIcon("pix/icons/document-open.png", "Open document");
@@ -50,15 +57,17 @@ public class Icons {
 	public static final Icon EDIT_COPY = loadImageIcon("pix/icons/edit-copy.png", "Copy");
 	public static final Icon EDIT_PASTE = loadImageIcon("pix/icons/edit-paste.png", "Paste");
 	public static final Icon EDIT_DELETE = loadImageIcon("pix/icons/edit-delete.png", "Delete");
-
+	
 	public static final Icon ZOOM_IN = loadImageIcon("pix/icons/zoom-in.png", "Zoom in");
 	public static final Icon ZOOM_OUT = loadImageIcon("pix/icons/zoom-out.png", "Zoom out");
-
+	
 	public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
-
+	
 	public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
 	
-	
+	static {
+		log.debug("Icons loaded");
+	}
 	
 	/**
 	 * Load an ImageIcon from the specified file.  The file is obtained as a system
diff --git a/src/net/sf/openrocket/util/Prefs.java b/src/net/sf/openrocket/util/Prefs.java
index c8ed58b92..8f5a75ec5 100644
--- a/src/net/sf/openrocket/util/Prefs.java
+++ b/src/net/sf/openrocket/util/Prefs.java
@@ -42,21 +42,21 @@ public class Prefs {
 	/**
 	 * Whether to use the debug-node instead of the normal node.
 	 */
-	public static final boolean DEBUG = false;
+	private static final boolean DEBUG;
+	static {
+		DEBUG = (System.getProperty("openrocket.debug.prefs") != null);
+	}
 	
 	/**
 	 * Whether to clear all preferences at application startup.  This has an effect only
 	 * if DEBUG is true.
 	 */
-	public static final boolean CLEARPREFS = true;
+	private static final boolean CLEARPREFS = true;
 	
 	/**
 	 * The node name to use in the Java preferences storage.
 	 */
-	public static final String NODENAME = (DEBUG ? "OpenRocket-debug" : "OpenRocket");
-	
-
-	public static final String DEFAULT_BUILD_SOURCE = "default";
+	private static final String NODENAME = (DEBUG ? "OpenRocket-debug" : "OpenRocket");
 	
 	
 	/*
@@ -128,6 +128,11 @@ public class Prefs {
 	private static final String CHECK_UPDATES = "CheckUpdates";
 	public static final String LAST_UPDATE = "LastUpdateVersion";
 	
+
+	// Node names
+	public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";
+	
+
 	/**
 	 * Node to this application's preferences.
 	 * @deprecated  Use the static methods instead.
@@ -137,6 +142,7 @@ public class Prefs {
 	private static final Preferences PREFNODE;
 	
 
+	// Clear the preferences if debug mode and clearprefs is defined
 	static {
 		Preferences root = Preferences.userRoot();
 		if (DEBUG && CLEARPREFS) {
@@ -193,16 +199,27 @@ public class Prefs {
 	//////////////////////
 	
 
+	/**
+	 * Return the OpenRocket version number.
+	 */
 	public static String getVersion() {
 		return BuildPropertyHolder.BUILD_VERSION;
 	}
 	
 	
+	/**
+	 * Return the OpenRocket build source (e.g. "default" or "Debian")
+	 */
 	public static String getBuildSource() {
 		return BuildPropertyHolder.BUILD_SOURCE;
 	}
 	
 	
+	/**
+	 * Return the OpenRocket unique ID.
+	 * 
+	 * @return	a random ID string that stays constant between OpenRocket executions
+	 */
 	public static String getUniqueID() {
 		String id = PREFNODE.get("id", null);
 		if (id == null) {
@@ -214,7 +231,10 @@ public class Prefs {
 	
 	
 
-	public static void storeVersion() {
+	/**
+	 * Store the current OpenRocket version into the preferences to allow for preferences migration.
+	 */
+	private static void storeVersion() {
 		PREFNODE.put("OpenRocketVersion", getVersion());
 	}
 	
@@ -249,27 +269,66 @@ public class Prefs {
 	}
 	
 	
-
+	/**
+	 * Return a string preference.
+	 * 
+	 * @param key	the preference key.
+	 * @param def	the default if no preference is stored
+	 * @return		the preference value
+	 */
 	public static String getString(String key, String def) {
 		return PREFNODE.get(key, def);
 	}
 	
+	/**
+	 * Set a string preference.
+	 * 
+	 * @param key		the preference key
+	 * @param value		the value to set
+	 */
 	public static void putString(String key, String value) {
 		PREFNODE.put(key, value);
 		storeVersion();
 	}
 	
-	
+	/**
+	 * Return a boolean preference.
+	 * 
+	 * @param key	the preference key
+	 * @param def	the default if no preference is stored
+	 * @return		the preference value
+	 */
 	public static boolean getBoolean(String key, boolean def) {
 		return PREFNODE.getBoolean(key, def);
 	}
 	
+	/**
+	 * Set a boolean preference.
+	 * 
+	 * @param key		the preference key
+	 * @param value		the value to set
+	 */
 	public static void putBoolean(String key, boolean value) {
 		PREFNODE.putBoolean(key, value);
 		storeVersion();
 	}
 	
 	
+	/**
+	 * Return a preferences object for the specified node name.
+	 * 
+	 * @param nodeName	the node name
+	 * @return			the preferences object for that node
+	 */
+	public static Preferences getNode(String nodeName) {
+		return PREFNODE.node(nodeName);
+	}
+	
+	
+	//////////////////
+	
+
+
 
 	public static boolean getCheckUpdates() {
 		return PREFNODE.getBoolean(CHECK_UPDATES, BuildPropertyHolder.DEFAULT_CHECK_UPDATES);
@@ -280,9 +339,6 @@ public class Prefs {
 		storeVersion();
 	}
 	
-	
-	//////////////////
-	
 	public static File getDefaultDirectory() {
 		String file = PREFNODE.get("defaultDirectory", null);
 		if (file == null)
diff --git a/src/net/sf/openrocket/util/TestRockets.java b/src/net/sf/openrocket/util/TestRockets.java
index 6b5b83f70..cf6b2787a 100644
--- a/src/net/sf/openrocket/util/TestRockets.java
+++ b/src/net/sf/openrocket/util/TestRockets.java
@@ -3,7 +3,6 @@ package net.sf.openrocket.util;
 import java.awt.Color;
 import java.util.Random;
 
-import net.sf.openrocket.database.Databases;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.material.Material.Type;
 import net.sf.openrocket.motor.Motor;
@@ -30,6 +29,7 @@ import net.sf.openrocket.rocketcomponent.FinSet.CrossSection;
 import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent;
 import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
 import net.sf.openrocket.rocketcomponent.Transition.Shape;
+import net.sf.openrocket.startup.Application;
 
 public class TestRockets {
 	
@@ -38,18 +38,18 @@ public class TestRockets {
 	
 	
 	public TestRockets(String key) {
-
+		
 		if (key == null) {
 			Random rnd = new Random();
 			StringBuilder sb = new StringBuilder();
-			for (int i=0; i<6; i++) {
+			for (int i = 0; i < 6; i++) {
 				int n = rnd.nextInt(62);
 				if (n < 10) {
-					sb.append((char)('0'+n));
+					sb.append((char) ('0' + n));
 				} else if (n < 36) {
-					sb.append((char)('A'+n-10));
+					sb.append((char) ('A' + n - 10));
 				} else {
-					sb.append((char)('a'+n-36));
+					sb.append((char) ('a' + n - 36));
 				}
 			}
 			key = sb.toString();
@@ -57,10 +57,10 @@ public class TestRockets {
 		
 		this.key = key;
 		this.rnd = new Random(key.hashCode());
-
+		
 	}
-
-
+	
+	
 	/**
 	 * Create a new test rocket based on the value 'key'.  The rocket utilizes most of the 
 	 * properties and features available.  The same key always returns the same rocket,
@@ -82,12 +82,12 @@ public class TestRockets {
 		rocket.setRevision("Rocket revision " + key);
 		rocket.setName(key);
 		
-		
+
 		Stage stage = new Stage();
 		setBasics(stage);
 		rocket.addChild(stage);
 		
-		
+
 		NoseCone nose = new NoseCone();
 		setBasics(stage);
 		nose.setAftRadius(rnd(0.03));
@@ -99,13 +99,13 @@ public class TestRockets {
 		nose.setClipped(rnd.nextBoolean());
 		nose.setThickness(rnd(0.002));
 		nose.setFilled(rnd.nextBoolean());
-		nose.setForeRadius(rnd(0.1));  // Unset
+		nose.setForeRadius(rnd(0.1)); // Unset
 		nose.setLength(rnd(0.15));
 		nose.setShapeParameter(rnd(0.5));
 		nose.setType((Shape) randomEnum(Shape.class));
 		stage.addChild(nose);
 		
-		
+
 		Transition shoulder = new Transition();
 		setBasics(shoulder);
 		shoulder.setAftRadius(rnd(0.06));
@@ -129,21 +129,21 @@ public class TestRockets {
 		shoulder.setType((Shape) randomEnum(Shape.class));
 		stage.addChild(shoulder);
 		
-		
+
 		BodyTube body = new BodyTube();
 		setBasics(body);
 		body.setThickness(rnd(0.002));
 		body.setFilled(rnd.nextBoolean());
-		body.setIgnitionDelay(rnd.nextDouble()*3);
+		body.setIgnitionDelay(rnd.nextDouble() * 3);
 		body.setIgnitionEvent((IgnitionEvent) randomEnum(IgnitionEvent.class));
 		body.setLength(rnd(0.3));
 		body.setMotorMount(rnd.nextBoolean());
-		body.setMotorOverhang(rnd.nextGaussian()*0.03);
+		body.setMotorOverhang(rnd.nextGaussian() * 0.03);
 		body.setRadius(rnd(0.06));
 		body.setRadiusAutomatic(rnd.nextBoolean());
 		stage.addChild(body);
-
 		
+
 		Transition boattail = new Transition();
 		setBasics(boattail);
 		boattail.setAftRadius(rnd(0.03));
@@ -177,9 +177,9 @@ public class TestRockets {
 		mass.setRadius(rnd(0.05));
 		nose.addChild(mass);
 		
-		
-		
-		
+
+
+
 		return rocket;
 	}
 	
@@ -187,13 +187,13 @@ public class TestRockets {
 	private void setBasics(RocketComponent c) {
 		c.setComment(c.getComponentName() + " comment " + key);
 		c.setName(c.getComponentName() + " name " + key);
-
+		
 		c.setCGOverridden(rnd.nextBoolean());
 		c.setMassOverridden(rnd.nextBoolean());
 		c.setOverrideCGX(rnd(0.2));
 		c.setOverrideMass(rnd(0.05));
 		c.setOverrideSubcomponents(rnd.nextBoolean());
-
+		
 		if (c.isMassive()) {
 			// Only massive components are drawn
 			c.setColor(randomColor());
@@ -201,23 +201,23 @@ public class TestRockets {
 		}
 		
 		if (c instanceof ExternalComponent) {
-			ExternalComponent e = (ExternalComponent)c;
+			ExternalComponent e = (ExternalComponent) c;
 			e.setFinish((Finish) randomEnum(Finish.class));
 			double d = rnd(100);
-			e.setMaterial(Material.newMaterial(Type.BULK, "Testmat "+d, d, rnd.nextBoolean()));
+			e.setMaterial(Material.newMaterial(Type.BULK, "Testmat " + d, d, rnd.nextBoolean()));
 		}
 		
 		if (c instanceof InternalComponent) {
-			InternalComponent i = (InternalComponent)c;
+			InternalComponent i = (InternalComponent) c;
 			i.setRelativePosition((Position) randomEnum(Position.class));
 			i.setPositionValue(rnd(0.3));
 		}
 	}
 	
 	
-	
+
 	private double rnd(double scale) {
-		return (rnd.nextDouble()*0.2+0.9) * scale;
+		return (rnd.nextDouble() * 0.2 + 0.9) * scale;
 	}
 	
 	private Color randomColor() {
@@ -231,20 +231,19 @@ public class TestRockets {
 		
 		return values[rnd.nextInt(values.length)];
 	}
+	
+	
+
+
 
-	
-	
-	
-	
-	
 	public Rocket makeSmallFlyable() {
-		double noseconeLength=0.10,noseconeRadius=0.01;
-		double bodytubeLength=0.20,bodytubeRadius=0.01,bodytubeThickness=0.001;
-		
-		int finCount=3;
-		double finRootChord=0.04,finTipChord=0.05,finSweep=0.01,finThickness=0.003, finHeight=0.03;
+		double noseconeLength = 0.10, noseconeRadius = 0.01;
+		double bodytubeLength = 0.20, bodytubeRadius = 0.01, bodytubeThickness = 0.001;
 		
+		int finCount = 3;
+		double finRootChord = 0.04, finTipChord = 0.05, finSweep = 0.01, finThickness = 0.003, finHeight = 0.03;
 		
+
 		Rocket rocket;
 		Stage stage;
 		NoseCone nosecone;
@@ -254,21 +253,21 @@ public class TestRockets {
 		rocket = new Rocket();
 		stage = new Stage();
 		stage.setName("Stage1");
-
-		nosecone = new NoseCone(Transition.Shape.ELLIPSOID,noseconeLength,noseconeRadius);
-		bodytube = new BodyTube(bodytubeLength,bodytubeRadius,bodytubeThickness);
-
-		finset = new TrapezoidFinSet(finCount,finRootChord,finTipChord,finSweep,finHeight);
 		
+		nosecone = new NoseCone(Transition.Shape.ELLIPSOID, noseconeLength, noseconeRadius);
+		bodytube = new BodyTube(bodytubeLength, bodytubeRadius, bodytubeThickness);
 		
+		finset = new TrapezoidFinSet(finCount, finRootChord, finTipChord, finSweep, finHeight);
+		
+
 		// Stage construction
 		rocket.addChild(stage);
-
 		
+
 		// Component construction
 		stage.addChild(nosecone);
 		stage.addChild(bodytube);
-
+		
 		bodytube.addChild(finset);
 		
 		Material material = Prefs.getDefaultComponentMaterial(null, Material.Type.BULK);
@@ -279,22 +278,18 @@ public class TestRockets {
 		String id = rocket.newMotorConfigurationID();
 		bodytube.setMotorMount(true);
 		
-		for (Motor m: Databases.MOTOR) {
-			if (m.getDesignation().equals("B4")) {
-				bodytube.setMotor(id, m);
-				break;
-			}
-		}
+		Motor m = Application.getMotorSetDatabase().findMotors(null, null, "B4", Double.NaN, Double.NaN).get(0);
+		bodytube.setMotor(id, m);
 		bodytube.setMotorOverhang(0.005);
 		rocket.getDefaultConfiguration().setMotorConfigurationID(id);
 		
 		rocket.getDefaultConfiguration().setAllStages();
 		
-		
+
 		return rocket;
 	}
-
-
+	
+	
 	public static Rocket makeBigBlue() {
 		Rocket rocket;
 		Stage stage;
@@ -306,11 +301,11 @@ public class TestRockets {
 		rocket = new Rocket();
 		stage = new Stage();
 		stage.setName("Stage1");
-
-		nosecone = new NoseCone(Transition.Shape.ELLIPSOID,0.105,0.033);
+		
+		nosecone = new NoseCone(Transition.Shape.ELLIPSOID, 0.105, 0.033);
 		nosecone.setThickness(0.001);
-		bodytube = new BodyTube(0.69,0.033,0.001);
-
+		bodytube = new BodyTube(0.69, 0.033, 0.001);
+		
 		finset = new FreeformFinSet();
 		try {
 			finset.setPoints(new Coordinate[] {
@@ -326,46 +321,42 @@ public class TestRockets {
 		finset.setThickness(0.003);
 		finset.setFinCount(4);
 		
-		finset.setCantAngle(0*Math.PI/180);
-		System.err.println("Fin cant angle: "+(finset.getCantAngle() * 180/Math.PI));
+		finset.setCantAngle(0 * Math.PI / 180);
+		System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
 		
-		mcomp = new MassComponent(0.2,0.03,0.045 + 0.060);
+		mcomp = new MassComponent(0.2, 0.03, 0.045 + 0.060);
 		mcomp.setRelativePosition(Position.TOP);
 		mcomp.setPositionValue(0);
 		
 		// Stage construction
 		rocket.addChild(stage);
 		rocket.setPerfectFinish(false);
-
 		
+
 		// Component construction
 		stage.addChild(nosecone);
 		stage.addChild(bodytube);
-
+		
 		bodytube.addChild(finset);
 		
 		bodytube.addChild(mcomp);
 		
-//		Material material = new Material("Test material", 500);
-//		nosecone.setMaterial(material);
-//		bodytube.setMaterial(material);
-//		finset.setMaterial(material);
+		//		Material material = new Material("Test material", 500);
+		//		nosecone.setMaterial(material);
+		//		bodytube.setMaterial(material);
+		//		finset.setMaterial(material);
 		
 		String id = rocket.newMotorConfigurationID();
 		bodytube.setMotorMount(true);
 		
-		for (Motor m: Databases.MOTOR) {
-			if (m.getDesignation().equals("F12J")) {
-				bodytube.setMotor(id, m);
-				break;
-			}
-		}
+		Motor m = Application.getMotorSetDatabase().findMotors(null, null, "F12J", Double.NaN, Double.NaN).get(0);
+		bodytube.setMotor(id, m);
 		bodytube.setMotorOverhang(0.005);
 		rocket.getDefaultConfiguration().setMotorConfigurationID(id);
 		
 		rocket.getDefaultConfiguration().setAllStages();
 		
-		
+
 		return rocket;
 	}
 	
@@ -385,29 +376,29 @@ public class TestRockets {
 		rocket = new Rocket();
 		stage = new Stage();
 		stage.setName("Stage1");
-
-		nosecone = new NoseCone(Transition.Shape.OGIVE,0.53,R);
+		
+		nosecone = new NoseCone(Transition.Shape.OGIVE, 0.53, R);
 		nosecone.setThickness(0.005);
 		nosecone.setMassOverridden(true);
 		nosecone.setOverrideMass(0.588);
 		stage.addChild(nosecone);
 		
-		tube1 = new BodyTube(0.505,R,0.005);
+		tube1 = new BodyTube(0.505, R, 0.005);
 		tube1.setMassOverridden(true);
 		tube1.setOverrideMass(0.366);
 		stage.addChild(tube1);
 		
-		tube2 = new BodyTube(0.605,R,0.005);
+		tube2 = new BodyTube(0.605, R, 0.005);
 		tube2.setMassOverridden(true);
 		tube2.setOverrideMass(0.427);
 		stage.addChild(tube2);
 		
-		tube3 = new BodyTube(1.065,R,0.005);
+		tube3 = new BodyTube(1.065, R, 0.005);
 		tube3.setMassOverridden(true);
 		tube3.setOverrideMass(0.730);
 		stage.addChild(tube3);
 		
-		
+
 		LaunchLug lug = new LaunchLug();
 		tube1.addChild(lug);
 		
@@ -421,7 +412,7 @@ public class TestRockets {
 		coupler.setPositionValue(-0.14);
 		tube1.addChild(coupler);
 		
-		
+
 		// Parachute
 		MassComponent mass = new MassComponent(0.05, 0.05, 0.280);
 		mass.setRelativePosition(Position.TOP);
@@ -440,7 +431,7 @@ public class TestRockets {
 		mass.setPositionValue(0.25);
 		tube1.addChild(mass);
 		
-		
+
 		auxfinset = new TrapezoidFinSet();
 		auxfinset.setName("CONTROL");
 		auxfinset.setFinCount(2);
@@ -452,12 +443,12 @@ public class TestRockets {
 		auxfinset.setCrossSection(CrossSection.AIRFOIL);
 		auxfinset.setRelativePosition(Position.TOP);
 		auxfinset.setPositionValue(0.28);
-		auxfinset.setBaseRotation(Math.PI/2);
+		auxfinset.setBaseRotation(Math.PI / 2);
 		tube1.addChild(auxfinset);
 		
-		
-		
-		
+
+
+
 		coupler = new TubeCoupler();
 		coupler.setOuterRadiusAutomatic(true);
 		coupler.setLength(0.28);
@@ -467,8 +458,8 @@ public class TestRockets {
 		coupler.setOverrideMass(0.360);
 		tube2.addChild(coupler);
 		
-		
-		
+
+
 		// Parachute
 		mass = new MassComponent(0.1, 0.05, 0.028);
 		mass.setRelativePosition(Position.TOP);
@@ -489,17 +480,17 @@ public class TestRockets {
 		mass.setPositionValue(0.19);
 		tube2.addChild(mass);
 		
-		
-		
+
+
 		InnerTube inner = new InnerTube();
-		inner.setOuterRadius(0.08/2);
-		inner.setInnerRadius(0.0762/2);
+		inner.setOuterRadius(0.08 / 2);
+		inner.setInnerRadius(0.0762 / 2);
 		inner.setLength(0.86);
 		inner.setMassOverridden(true);
 		inner.setOverrideMass(0.388);
 		tube3.addChild(inner);
 		
-		
+
 		CenteringRing center = new CenteringRing();
 		center.setInnerRadiusAutomatic(true);
 		center.setOuterRadiusAutomatic(true);
@@ -510,7 +501,7 @@ public class TestRockets {
 		center.setPositionValue(0);
 		tube3.addChild(center);
 		
-		
+
 		center = new CenteringRing();
 		center.setInnerRadiusAutomatic(true);
 		center.setOuterRadiusAutomatic(true);
@@ -521,7 +512,7 @@ public class TestRockets {
 		center.setPositionValue(0.28);
 		tube3.addChild(center);
 		
-		
+
 		center = new CenteringRing();
 		center.setInnerRadiusAutomatic(true);
 		center.setOuterRadiusAutomatic(true);
@@ -532,10 +523,10 @@ public class TestRockets {
 		center.setPositionValue(0.83);
 		tube3.addChild(center);
 		
-		
-		
-		
-		
+
+
+
+
 		finset = new TrapezoidFinSet();
 		finset.setRootChord(0.495);
 		finset.setTipChord(0.1);
@@ -544,40 +535,36 @@ public class TestRockets {
 		finset.setSweep(0.3);
 		finset.setRelativePosition(Position.BOTTOM);
 		finset.setPositionValue(-0.03);
-		finset.setBaseRotation(Math.PI/2);
+		finset.setBaseRotation(Math.PI / 2);
 		tube3.addChild(finset);
 		
+
+		finset.setCantAngle(0 * Math.PI / 180);
+		System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
 		
-		finset.setCantAngle(0*Math.PI/180);
-		System.err.println("Fin cant angle: "+(finset.getCantAngle() * 180/Math.PI));
-		
-		
+
 		// Stage construction
 		rocket.addChild(stage);
 		rocket.setPerfectFinish(false);
+		
+
 
-		
-		
 		String id = rocket.newMotorConfigurationID();
 		tube3.setMotorMount(true);
 		
-		for (Motor m: Databases.MOTOR) {
-			if (m.getDesignation().equals("L540")) {
-				tube3.setMotor(id, m);
-				break;
-			}
-		}
+		Motor m = Application.getMotorSetDatabase().findMotors(null, null, "L540", Double.NaN, Double.NaN).get(0);
+		tube3.setMotor(id, m);
 		tube3.setMotorOverhang(0.02);
 		rocket.getDefaultConfiguration().setMotorConfigurationID(id);
-
-//		tube3.setIgnitionEvent(MotorMount.IgnitionEvent.NEVER);
+		
+		//		tube3.setIgnitionEvent(MotorMount.IgnitionEvent.NEVER);
 		
 		rocket.getDefaultConfiguration().setAllStages();
 		
-		
+
 		return rocket;
 	}
 	
-	
-	
+
+
 }
diff --git a/test/net/sf/openrocket/database/MotorSetDatabaseTest.java b/test/net/sf/openrocket/database/MotorSetDatabaseTest.java
index 663340f8c..33ced0c8e 100644
--- a/test/net/sf/openrocket/database/MotorSetDatabaseTest.java
+++ b/test/net/sf/openrocket/database/MotorSetDatabaseTest.java
@@ -17,7 +17,7 @@ public class MotorSetDatabaseTest {
 	@Test
 	public void testMotorLoading() {
 		
-		MotorSetDatabase db = new MotorSetDatabase(true) {
+		ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(true) {
 			@Override
 			protected void loadMotors() {
 				try {