diff --git a/core/.classpath b/core/.classpath
index acc55d845..453ab552f 100644
--- a/core/.classpath
+++ b/core/.classpath
@@ -15,6 +15,8 @@
 	<classpathentry kind="lib" path="lib-extra/RXTXcomm.jar"/>
 	<classpathentry kind="lib" path="resources"/>
 	<classpathentry kind="lib" path="lib/javax.inject.jar"/>
+	<classpathentry kind="lib" path="lib/javax.json-1.1.3.jar"/>
+	<classpathentry kind="lib" path="lib/javax.json-api-1.1.3.jar"/>
 	<classpathentry kind="lib" path="lib/aopalliance.jar"/>
 	<classpathentry kind="lib" path="lib/commonmark-0.19.0.jar"/>
 	<classpathentry kind="lib" path="lib/slf4j-api-1.7.30.jar"/>
diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index aa9ae51b7..e70342af9 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -294,6 +294,8 @@ pref.dlg.lbl.PositiontoinsertStages = Position to insert new stages:
 pref.dlg.lbl.Confirmdeletion = Confirm deletion of simulations.
 pref.dlg.checkbox.Runsimulations = Run out-dated simulations when you open the simulation tab.
 pref.dlg.checkbox.Updateestimates = Update estimated flight parameters in design window
+pref.dlg.checkbox.Markers = Only show pod set/booster markers when the pod set/booster is selected
+pref.dlg.checkbox.Markers.ttip = <html>If checked, pod set/booster markers will only be shown when the pod set/booster is selected.<br>If unchecked, pod set/booster markers will always be shown.</html>
 pref.dlg.checkbox.AlwaysOpenLeftmost = Always open leftmost tab when opening a component edit dialog
 pref.dlg.checkbox.AlwaysOpenLeftmost.ttip = <html>If checked, a component edit dialog will always pop up with the first tab selected.<br>If unchecked, the previous selected tab will be used.</html>
 pref.dlg.lbl.User-definedthrust = User-defined thrust curves:
@@ -715,7 +717,7 @@ compaddbuttons.Launchlug = Launch Lug
 compaddbuttons.RailButton = Rail Button
 compaddbuttons.InnerComponent = Inner Components
 compaddbuttons.Innertube = Inner Tube
-compaddbuttons.Coupler = Coupler
+compaddbuttons.Coupler = Tube Coupler
 compaddbuttons.Centeringring = Centering\nRing
 compaddbuttons.Bulkhead = Bulkhead
 compaddbuttons.Engineblock = Engine\nBlock
@@ -887,16 +889,17 @@ RocketCfg.lbl.Material = Material:
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = Component name:
-RocketCompCfg.ttip.Thecomponentname = The component name.
+RocketCompCfg.lbl.Componentname.ttip = The component name.
 RocketCompCfg.tab.Override = Override
-RocketCompCfg.tab.MassandCGoverride = Mass and CG override options
+RocketCompCfg.tab.Override.ttip = Mass and CG override options
 RocketCompCfg.tab.Assembly = General
 RocketCompCfg.tab.AssemblyComment = Options for locating stages parallel to other stages
 RocketCompCfg.tab.Figure = Figure
 RocketCompCfg.tab.Figstyleopt = Figure style options
 RocketCompCfg.tab.Comment = Comment
-RocketCompCfg.tab.Specifyacomment = Specify a comment for the component
-RocketCompCfg.tab.Appearance                      = Appearance
+RocketCompCfg.tab.Comment.ttip = Specify a comment for the component
+RocketCompCfg.tab.Appearance  = Appearance
+RocketCompCfg.tab.Appearance.ttip  = Component's appearance
 RocketCompCfg.lbl.Mass = Mass:
 RocketCompCfg.lbl.Componentmass = Component mass:
 RocketCompCfg.lbl.overriddento = (overridden to
@@ -2071,8 +2074,10 @@ CustomFinImport.error.badimage = Could not deduce fin shape from image.
 CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
 
 
-PresetModel.lbl.select = Select preset
-PresetModel.lbl.database = From database\u2026
+PresetModel.combo.ttip = <html>Select a preset model from a list of favorites (selected in the component preset dialog),<br>or select 'Custom' when no preset is required.</html>
+PresetModel.lbl.custompreset = Custom
+PresetModel.lbl.partsLib = Parts Library
+PresetModel.lbl.partsLib.ttip = Select a preset model for this rocket component from a library of parts.
 
 DecalModel.lbl.select = <none>
 DecalModel.lbl.choose = From file\u2026
@@ -2094,7 +2099,7 @@ ComponentPresetChooserDialog.menu.sortDesc = Sort Descending
 ComponentPresetChooserDialog.menu.units = Units
 ComponentPresetChooserDialog.checkbox.showAllCompatible = Show all compatible
 ComponentPresetChooserDialog.checkbox.showLegacyCheckBox = Show Legacy Database
-ComponentPresetChooserDialog.lbl.favorites = Select to add preset to drop-down menu
+ComponentPresetChooserDialog.lbl.favorites = Check to add preset to the preset drop-down menu in the component edit dialog
 table.column.Favorite = Favorite
 table.column.Legacy = Legacy
 table.column.Manufacturer = Manufacturer
diff --git a/core/resources/l10n/messages_cs.properties b/core/resources/l10n/messages_cs.properties
index f5b5933f7..a30ef6392 100644
--- a/core/resources/l10n/messages_cs.properties
+++ b/core/resources/l10n/messages_cs.properties
@@ -621,13 +621,13 @@ ShockCordCfg.lbl.Shockcordlength = D
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = Jm�no komponenty:
-RocketCompCfg.ttip.Thecomponentname = Jm�no komponenty.
+RocketCompCfg.lbl.Componentname.ttip = Jm�no komponenty.
 RocketCompCfg.tab.Override = Prepsat
-RocketCompCfg.tab.MassandCGoverride = Prepi\u0161 hmotnost a te\u017Ei\u0161te
+RocketCompCfg.tab.Override.ttip = Prepi\u0161 hmotnost a te\u017Ei\u0161te
 RocketCompCfg.tab.Figure = Obr�zek
 RocketCompCfg.tab.Figstyleopt = Vlastnosti obr�zku
 RocketCompCfg.tab.Comment = Koment�r
-RocketCompCfg.tab.Specifyacomment = Upresnen� koment�re komponenty
+RocketCompCfg.tab.Comment.ttip = Upresnen� koment�re komponenty
 RocketCompCfg.lbl.Mass = Hmotnost:
 RocketCompCfg.lbl.Componentmass = Hmotnost komponenty:
 RocketCompCfg.lbl.overriddento = (preps�no na
@@ -1587,8 +1587,8 @@ CustomFinImport.error.badimage = Nemohu vyvodit tvar stabiliz
 CustomFinImport.description = Obr�zek bude zmenen na cernob�l� \n(cern� pro stabiliz�tor), ujistete se pros�m, \u017Ee jste pou\u017Eily cernou barvu na stabiliz�tor \na b�lou nebo svetlou barvu na pozad�. Stabiliz�tor \nse mus� dot�kat steny obr�zku, kter� predstavuje uchycen� pro stabiliz�tor.
 
 
-PresetModel.lbl.select = V�ber predvolby:
-PresetModel.lbl.database = Z datab�ze...
+PresetModel.lbl.custompreset = Vlastn�
+PresetModel.lbl.partsLib = Knihovna d�l?
 
 
 ! Component Preset Chooser Dialog
diff --git a/core/resources/l10n/messages_de.properties b/core/resources/l10n/messages_de.properties
index 45f91eda5..5a1d9a7ec 100644
--- a/core/resources/l10n/messages_de.properties
+++ b/core/resources/l10n/messages_de.properties
@@ -677,13 +677,13 @@ ShockCordCfg.lbl.Shockcordlength = Gummibandl
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = Komponentenname:
-RocketCompCfg.ttip.Thecomponentname = Name der Komponente.
+RocketCompCfg.lbl.Componentname.ttip = Name der Komponente.
 RocketCompCfg.tab.Override = Werte �berschreiben
-RocketCompCfg.tab.MassandCGoverride = Massen- und Schwerpunktsoptionen
+RocketCompCfg.tab.Override.ttip = Massen- und Schwerpunktsoptionen
 RocketCompCfg.tab.Figure = Form
 RocketCompCfg.tab.Figstyleopt = Formoptionen
 RocketCompCfg.tab.Comment = Kommentar
-RocketCompCfg.tab.Specifyacomment = Kommentar zu dieser Komponente
+RocketCompCfg.tab.Comment.ttip = Kommentar zu dieser Komponente
 RocketCompCfg.lbl.Mass = Masse:
 RocketCompCfg.lbl.Componentmass = Masse der Komponente:
 RocketCompCfg.lbl.overriddento = (�berschrieben auf
@@ -1645,8 +1645,8 @@ CustomFinImport.error.badimage = Konnte keine Leitwerksform aus dem Bild erzeuge
 CustomFinImport.description = Das Bild wird intern in ein Schwarz-Wei�-Bild konvertiert (Leitwerk: schwarz). Bitte sicherstellen, dass das Leitwerk in einer dichten, dunklen Farbe ist, w�hrend der Hintergrund wei� oder sehr hell sein sollte. Das Leitwerk muss das untere Bildende ber�hren, da dies die Verbindungsstelle zur Rakete wird.
 
 
-PresetModel.lbl.select = Voreinstellung ausw�hlen:
-PresetModel.lbl.database = Aus Datenbank...
+PresetModel.lbl.custompreset = Benutzerdefiniert
+PresetModel.lbl.partsLib = Teile-Bibliothek
 
 
 ! Component Preset Chooser Dialog
diff --git a/core/resources/l10n/messages_es.properties b/core/resources/l10n/messages_es.properties
index 255e26369..556fd9ede 100644
--- a/core/resources/l10n/messages_es.properties
+++ b/core/resources/l10n/messages_es.properties
@@ -737,8 +737,8 @@ PreferencesDialog.languages.default  = Idioma por defecto
 PreferencesDialog.lbl.language       = Idioma de la interfaz:
 PreferencesDialog.lbl.languageEffect = El idioma cambiar\u00e1 la pr\u00f3xima vez que abra OpenRocket.
 
-PresetModel.lbl.database = Desde la Base de Datos...
-PresetModel.lbl.select   = Prefabricado
+PresetModel.lbl.custompreset = Personalizado
+PresetModel.lbl.partsLib   = Biblioteca de piezas
 
 PrintDialog.but.previewAndPrint  = Vista previa e Imprimir
 PrintDialog.checkbox.showByStage = Mostrar por etapas
@@ -861,13 +861,13 @@ RocketCompCfg.tab.Appearance                      = Apariencia
 RocketCompCfg.tab.Comment                         = Comentarios
 RocketCompCfg.tab.Figstyleopt                     = Opciones de estilo de la figura
 RocketCompCfg.tab.Figure                          = Estilo
-RocketCompCfg.tab.MassandCGoverride               = Especificar la Masa y el CG del componente.
+RocketCompCfg.tab.Override.ttip               = Especificar la Masa y el CG del componente.
 RocketCompCfg.tab.Override                        = Masa y CG
-RocketCompCfg.tab.Specifyacomment                 = Especifique un comentario para el componente
+RocketCompCfg.tab.Comment.ttip                 = Especifique un comentario para el componente
 RocketCompCfg.title.Aftshoulder                   = Trasera del acople
 RocketCompCfg.title.Noseconeshoulder              = Acople de la ojiva
 RocketCompCfg.ttip.Endcapped                      = Si el extremo del soporte est\u00e1 truncado.
-RocketCompCfg.ttip.Thecomponentname               = El nombre del componente.
+RocketCompCfg.lbl.Componentname.ttip               = El nombre del componente.
 
 RocketComponent.Position.ABSOLUTE = Extremo de la ojiva
 RocketComponent.Position.AFTER    = Despu\u00e9s del componente
diff --git a/core/resources/l10n/messages_fr.properties b/core/resources/l10n/messages_fr.properties
index d4cee80d0..350bc5874 100644
--- a/core/resources/l10n/messages_fr.properties
+++ b/core/resources/l10n/messages_fr.properties
@@ -729,8 +729,8 @@ PreferencesDialog.languages.default  = Valeur syst\u00E8me par d\u00E9faut
 PreferencesDialog.lbl.language       = Langue du programme:
 PreferencesDialog.lbl.languageEffect = La langue sera chang\u00E9e apr\u00E8s avoir red\u00E9marr\u00E9 OpenRocket.
 
-PresetModel.lbl.database = A partir d'une base de donn\u00E9es...
-PresetModel.lbl.select   = Choisir une pi\u00E8ce pr\u00E9d\u00E9finie:
+PresetModel.lbl.custompreset = Personnalis�
+PresetModel.lbl.partsLib   = Biblioth\u00E8que de pi\u00E8ces
 
 PrintDialog.but.previewAndPrint  = Pr\u00E9-visualiser et imprimer
 PrintDialog.checkbox.showByStage = Montrer par \u00E9tage
@@ -853,13 +853,13 @@ RocketCompCfg.tab.Appearance                      = Apparence
 RocketCompCfg.tab.Comment                         = Commentaires
 RocketCompCfg.tab.Figstyleopt                     = Options de la forme
 RocketCompCfg.tab.Figure                          = Forme
-RocketCompCfg.tab.MassandCGoverride               = For\u00E7age de la Masse et du CG
+RocketCompCfg.tab.Override.ttip               = For\u00E7age de la Masse et du CG
 RocketCompCfg.tab.Override                        = Forcer la valeur
-RocketCompCfg.tab.Specifyacomment                 = Commentaires concernant la pi\u00E8ce
+RocketCompCfg.tab.Comment.ttip                 = Commentaires concernant la pi\u00E8ce
 RocketCompCfg.title.Aftshoulder                   = Epaulement arri\u00E8re
 RocketCompCfg.title.Noseconeshoulder              = Epaulement du c\u00F4ne
 RocketCompCfg.ttip.Endcapped                      = Pr\u00E9cise si l'arri\u00E8re du c\u00F4ne est clos.
-RocketCompCfg.ttip.Thecomponentname               = Le nom de la pi\u00E8ce.
+RocketCompCfg.lbl.Componentname.ttip               = Le nom de la pi\u00E8ce.
 
 RocketComponent.Position.ABSOLUTE = Pointe de l'ogive
 RocketComponent.Position.AFTER    = Apr\u00E8s la pi\u00E8ce parente
diff --git a/core/resources/l10n/messages_it.properties b/core/resources/l10n/messages_it.properties
index f99e43eb3..0596e8fc5 100644
--- a/core/resources/l10n/messages_it.properties
+++ b/core/resources/l10n/messages_it.properties
@@ -679,13 +679,13 @@ ShockCordCfg.lbl.Shockcordlength = Lunghezza della Shock cord :
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = Nome componente:
-RocketCompCfg.ttip.Thecomponentname = Il nome del componente.
+RocketCompCfg.lbl.Componentname.ttip = Il nome del componente.
 RocketCompCfg.tab.Override = Modifica
-RocketCompCfg.tab.MassandCGoverride = Opzioni di sovrascrittura di massa e CG 
+RocketCompCfg.tab.Override.ttip = Opzioni di sovrascrittura di massa e CG 
 RocketCompCfg.tab.Figure = Disegno
 RocketCompCfg.tab.Figstyleopt = Opzioni dello stile della figure 
 RocketCompCfg.tab.Comment = Commento
-RocketCompCfg.tab.Specifyacomment = Specifica un commento per il componente
+RocketCompCfg.tab.Comment.ttip = Specifica un commento per il componente
 RocketCompCfg.lbl.Mass = Massa:
 RocketCompCfg.lbl.Componentmass = La massa del componente :
 RocketCompCfg.lbl.overriddento = (sovrascritto a 
@@ -1651,8 +1651,8 @@ CustomFinImport.error.badimage   = Non riesco a capire la forma della pinna dall
 CustomFinImport.description      = L'immagine sar\u00e0 convertita in bianco e nero internamente (nero per le pinne), cos\u00ec assicurati di usare un nero pieno per le pinne e bianco, o colore chiaro, per lo sfondo. La pinna ndeve toccare il fondo dell'immagine, che \u00e8 la base della pinna.
 
 
-PresetModel.lbl.select = Seleziona precaricati:
-PresetModel.lbl.database = Da database...
+PresetModel.lbl.custompreset = Personalizzato
+PresetModel.lbl.partsLib = Libreria di parti
 
 
 ! Component Preset Chooser Dialog
diff --git a/core/resources/l10n/messages_ja.properties b/core/resources/l10n/messages_ja.properties
index 2417dd0c0..3daf4089e 100644
--- a/core/resources/l10n/messages_ja.properties
+++ b/core/resources/l10n/messages_ja.properties
@@ -709,13 +709,13 @@ ShockCordCfg.lbl.Shockcordlength  = \u30B7\u30E7\u30C3\u30AF\u30B3\u30FC\u30C9\u
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname  = \u90E8\u54C1\u540D\uFF1A
-RocketCompCfg.ttip.Thecomponentname  = \u90E8\u54C1\u306E\u540D\u524D
+RocketCompCfg.lbl.Componentname.ttip  = \u90E8\u54C1\u306E\u540D\u524D
 RocketCompCfg.tab.Override  = \u518D\u5B9A\u7FA9
-RocketCompCfg.tab.MassandCGoverride  = \u8CEA\u91CF\u3068CG\u3092\u518D\u5B9A\u7FA9\u3059\u308B\u30AA\u30D7\u30B7\u30E7\u30F3
+RocketCompCfg.tab.Override.ttip  = \u8CEA\u91CF\u3068CG\u3092\u518D\u5B9A\u7FA9\u3059\u308B\u30AA\u30D7\u30B7\u30E7\u30F3
 RocketCompCfg.tab.Figure  = \u56F3\u793A
 RocketCompCfg.tab.Figstyleopt  = \u56F3\u793A\u306E\u30B9\u30BF\u30A4\u30EB\u30AA\u30D7\u30B7\u30E7\u30F3
 RocketCompCfg.tab.Comment  = \u30B3\u30E1\u30F3\u30C8
-RocketCompCfg.tab.Specifyacomment  = \u90E8\u54C1\u3078\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u8A18\u8FF0
+RocketCompCfg.tab.Comment.ttip  = \u90E8\u54C1\u3078\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u8A18\u8FF0
 RocketCompCfg.lbl.Mass  = \u8CEA\u91CF\uFF1A
 RocketCompCfg.lbl.Componentmass  = \u90E8\u54C1\u8CEA\u91CF\uFF1A
 RocketCompCfg.lbl.overriddento  = (overridden to
@@ -1713,8 +1713,8 @@ CustomFinImport.error.badimage  = \u753B\u50CF\u304B\u3089\u30D5\u30A3\u30F3\u5F
 CustomFinImport.description  = \u753B\u50CF\u306F\u5185\u90E8\u3067\u767D\u80CC\u666F\u3068\u9ED2\u7DDA\u306B\u5909\u63DB\u3055\u308C\u307E\u3059\u3002\u306A\u306E\u3067\u30D5\u30A3\u30F3\u306B\u306F\u6697\u3044\u8272\u306E\u5B9F\u7DDA\u3001\u80CC\u666F\u306B\u306F\u767D\u304B\u660E\u308B\u3044\u8272\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D5\u30A3\u30F3\u306F\u753B\u50CF\u306E\u5E95\u9762\u306B\u63A5\u3057\u3066\u3044\u306A\u304F\u3066\u306F\u3044\u3051\u307E\u305B\u3093\u3001\u3053\u308C\u306F\u30D5\u30A3\u30F3\u306E\u5E95\u9762\u306B\u306A\u308A\u307E\u3059\u3002
 
 
-PresetModel.lbl.select  = Select preset
-PresetModel.lbl.database  = From database...
+PresetModel.lbl.custompreset  = \u30ab\u30b9\u30bf\u30e0
+PresetModel.lbl.partsLib  = \u30d1\u30fc\u30c4\u30e9\u30a4\u30d6\u30e9\u30ea\u30fc
 
 
 ! Component Preset Chooser Dialog
diff --git a/core/resources/l10n/messages_nl.properties b/core/resources/l10n/messages_nl.properties
index b32a8d0a5..08c3faeed 100644
--- a/core/resources/l10n/messages_nl.properties
+++ b/core/resources/l10n/messages_nl.properties
@@ -826,15 +826,15 @@ RocketCfg.lbl.Material = Materiaal:
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = Componentnaam:
-RocketCompCfg.ttip.Thecomponentname = De componentnaam.
+RocketCompCfg.lbl.Componentname.ttip = De componentnaam.
 RocketCompCfg.tab.Override = Overschrijf
-RocketCompCfg.tab.MassandCGoverride = Massa en ZP overschrijvingsopties
+RocketCompCfg.tab.Override.ttip = Massa en ZP overschrijvingsopties
 RocketCompCfg.tab.Assembly = Algemeen
 RocketCompCfg.tab.AssemblyComment = Opties voor het plaatsen van trappen parallel aan andere trappen
 RocketCompCfg.tab.Figure = Figuur
 RocketCompCfg.tab.Figstyleopt = Figuurstijl opties
 RocketCompCfg.tab.Comment = Opmerking
-RocketCompCfg.tab.Specifyacomment = Geef een opmerking voor het onderdeel
+RocketCompCfg.tab.Comment.ttip = Geef een opmerking voor het onderdeel
 RocketCompCfg.tab.Appearance = Uiterlijk
 RocketCompCfg.lbl.Mass = Massa:
 RocketCompCfg.lbl.Componentmass = Componentmassa:
@@ -1967,8 +1967,8 @@ CustomFinImport.error.badimage = Kon de vorm van de vin niet afleiden uit het be
 CustomFinImport.description = De afbeelding wordt intern geconverteerd naar een zwart-wit afbeelding (zwart voor de vin), dus zorg ervoor dat je een effen donkere kleur gebruikt voor de vin, en wit of een lichte kleur voor de achtergrond. De vin moet de onderkant van het beeld raken, dat is de basis van de vin.
 
 
-PresetModel.lbl.select = Selecteer preset
-PresetModel.lbl.database = Uit databank...
+PresetModel.lbl.custompreset = Aangepast
+PresetModel.lbl.partsLib = Onderdelenbibliotheek
 
 DecalModel.lbl.select = <geen>
 DecalModel.lbl.choose = Van bestand...
diff --git a/core/resources/l10n/messages_pl.properties b/core/resources/l10n/messages_pl.properties
index 08bcaec77..4c1cefc01 100644
--- a/core/resources/l10n/messages_pl.properties
+++ b/core/resources/l10n/messages_pl.properties
@@ -623,13 +623,13 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
  
  ! RocketComponentConfig
  RocketCompCfg.lbl.Componentname  =  Nazwa cz\u0119\u015Bci:
- RocketCompCfg.ttip.Thecomponentname  =  Nazwa cz\u0119\u015Bci sk\u0142adowej rakiety.
+ RocketCompCfg.lbl.Componentname.ttip  =  Nazwa cz\u0119\u015Bci sk\u0142adowej rakiety.
  RocketCompCfg.tab.Override  =  Wymu\u015B
- RocketCompCfg.tab.MassandCGoverride  =  Opcje wymuszenia ci\u0119\u017Caru oraz \u015Brodka ci\u0119\u017Cko\u015Bci
+ RocketCompCfg.tab.Override.ttip  =  Opcje wymuszenia ci\u0119\u017Caru oraz \u015Brodka ci\u0119\u017Cko\u015Bci
  RocketCompCfg.tab.Figure  =  Wygl\u0105d
  RocketCompCfg.tab.Figstyleopt  =  Styl kszta\u0142tu
  RocketCompCfg.tab.Comment  =  Uwagi
- RocketCompCfg.tab.Specifyacomment  =  Dodaj uwagi do cz\u0119\u015Bci
+ RocketCompCfg.tab.Comment.ttip  =  Dodaj uwagi do cz\u0119\u015Bci
  RocketCompCfg.lbl.Mass  =  Masa:
  RocketCompCfg.lbl.Componentmass  =  Masa cz\u0119\u015Bci:
  RocketCompCfg.lbl.overriddento  =  (wymuszone do
@@ -1592,8 +1592,8 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
  CustomFinImport.description  =  Obraz zostanie automatycznie zamieniony na czarno-bia\u0142y (statecznik w kolorze czarnym), wi\u0119c upewnij si\u0119, \u017Ce kszta\u0142t statecznika jest wype\u0142niony ciemnym kolorem, a t\u0142o jest bia\u0142e lub jasne. Podstawa statecznika musi przylega\u0107 do dolnej kraw\u0119dzi obrazu.
  
  
- PresetModel.lbl.select  =  Wybierz ustawienia:
- PresetModel.lbl.database  =  Z bazy danych...
+ PresetModel.lbl.custompreset  = Niestandardowe
+ PresetModel.lbl.partsLib  = Biblioteka cz??ci
  
  
  ! Component Preset Chooser Dialog
diff --git a/core/resources/l10n/messages_pt.properties b/core/resources/l10n/messages_pt.properties
index c40699812..18ce530f8 100644
--- a/core/resources/l10n/messages_pt.properties
+++ b/core/resources/l10n/messages_pt.properties
@@ -715,8 +715,8 @@ PreferencesDialog.languages.default  = Padr\u00e3o do sistema
 PreferencesDialog.lbl.language       = Idioma da interface:
 PreferencesDialog.lbl.languageEffect = A linguagem vai mudar na pr\u00f3xima vez que voc\u00ea iniciar o OpenRocket.
 
-PresetModel.lbl.database = \u00c0 partir do banco de dados...
-PresetModel.lbl.select   = Selecione ajustes pr\u00e9-definidos
+PresetModel.lbl.custompreset   = Personalizado
+PresetModel.lbl.partsLib   = Biblioteca de pe\u00e7as
 
 PrintDialog.but.previewAndPrint  = Visualiza\u00e7\u00e3o e impress\u00e3o
 PrintDialog.checkbox.showByStage = Mostrar por est\u00e1gio
@@ -838,13 +838,13 @@ RocketCompCfg.lbl.ttip.componentmaterialaffects   = O material do componente afe
 RocketCompCfg.tab.Comment                         = Coment\u00e1rio
 RocketCompCfg.tab.Figstyleopt                     = Op\u00e7\u00f5es do estilo de figura
 RocketCompCfg.tab.Figure                          = Figura
-RocketCompCfg.tab.MassandCGoverride               = Op\u00e7\u00f5es de modifica\u00e7\u00e3o de massa e CG
+RocketCompCfg.tab.Override.ttip               = Op\u00e7\u00f5es de modifica\u00e7\u00e3o de massa e CG
 RocketCompCfg.tab.Override                        = Modificar
-RocketCompCfg.tab.Specifyacomment                 = Especifique um coment\u00e1rio para o componente
+RocketCompCfg.tab.Comment.ttip                 = Especifique um coment\u00e1rio para o componente
 RocketCompCfg.title.Aftshoulder                   = Ressalto traseiro
 RocketCompCfg.title.Noseconeshoulder              = Ressalto da ogiva
 RocketCompCfg.ttip.Endcapped                      = Quando a extremidade do ressalto \u00e9 limitada.
-RocketCompCfg.ttip.Thecomponentname               = Nome do componente.
+RocketCompCfg.lbl.Componentname.ttip               = Nome do componente.
 
 RocketComponent.Position.ABSOLUTE = Dica da ogiva
 RocketComponent.Position.AFTER    = Depois do componente pai
diff --git a/core/resources/l10n/messages_ru.properties b/core/resources/l10n/messages_ru.properties
index f7eeb8792..2ae02679c 100644
--- a/core/resources/l10n/messages_ru.properties
+++ b/core/resources/l10n/messages_ru.properties
@@ -888,15 +888,15 @@ RocketCfg.lbl.Material = \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B:
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.ttip.Thecomponentname = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430.
+RocketCompCfg.lbl.Componentname.ttip = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430.
 RocketCompCfg.tab.Override = \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435
-RocketCompCfg.tab.MassandCGoverride = \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u0438 \u0426\u0422
+RocketCompCfg.tab.Override.ttip = \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u0438 \u0426\u0422
 RocketCompCfg.tab.Assembly = \u0421\u0431\u043E\u0440\u043A\u0430
 RocketCompCfg.tab.AssemblyComment = \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0440\u0430\u0437\u043C\u0435\u0449\u0435\u043D\u0438\u044F \u0441\u0442\u0443\u043F\u0435\u043D\u0435\u0439 \u043F\u0430\u0440\u0430\u043B\u043B\u0435\u043B\u044C\u043D\u043E \u0434\u0440\u0443\u0433\u0438\u043C \u0441\u0442\u0443\u043F\u0435\u043D\u044F\u043C
 RocketCompCfg.tab.Figure = \u0420\u0438\u0441\u0443\u043D\u043E\u043A
 RocketCompCfg.tab.Figstyleopt = \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0441\u0442\u0438\u043B\u044F \u0440\u0438\u0441\u0443\u043D\u043A\u0430
 RocketCompCfg.tab.Comment = \u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435
-RocketCompCfg.tab.Specifyacomment = \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043A \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0443
+RocketCompCfg.tab.Comment.ttip = \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043A \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0443
 RocketCompCfg.tab.Appearance = \u0412\u043D\u0435\u0448\u043D\u0438\u0439 \u0432\u0438\u0434
 RocketCompCfg.lbl.Mass = \u041C\u0430\u0441\u0441\u0430:
 RocketCompCfg.lbl.Componentmass = \u041C\u0430\u0441\u0441\u0430 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
@@ -2075,8 +2075,8 @@ CustomFinImport.error.badimage = \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u043
 CustomFinImport.description = \u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044F \u0432 \u0447\u0435\u0440\u043D\u043E-\u0431\u0435\u043B\u043E\u0435 (\u0433\u0434\u0435 \u0447\u0435\u0440\u043D\u044B\u0439 - \u0446\u0432\u0435\u0442 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430), \u0442\u0430\u043A \u0447\u0442\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u0447\u0435\u0440\u043D\u044B\u0439 \u0446\u0432\u0435\u0442 \u0434\u043B\u044F \u0440\u0438\u0441\u0443\u043D\u043A\u0430 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430 \u0438 \u0431\u0435\u043B\u044B\u0439 \u0438\u043B\u0438 \u0441\u0432\u0435\u0442\u043B\u044B\u0439 \u0446\u0432\u0435\u0442 \u0434\u043B\u044F \u0444\u043E\u043D\u0430. \u041E\u0441\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430 \u0434\u043E\u043B\u0436\u043D\u043E \u043D\u0430\u0447\u0438\u043D\u0430\u0442\u044C\u0441\u044F \u0441\u043D\u0438\u0437\u0443 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F.
 
 
-PresetModel.lbl.select = \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0433\u043E\u0442\u043E\u0432\u043A\u0443
-PresetModel.lbl.database = \u0418\u0437 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445...
+PresetModel.lbl.custompreset = \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0020\u0434\u0435\u0442\u0430\u043b\u0435\u0439
+PresetModel.lbl.partsLib = \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0020\u0434\u0435\u0442\u0430\u043b\u0435\u0439
 
 DecalModel.lbl.select = <\u043D\u0435\u0442>
 DecalModel.lbl.choose = \u0418\u0437 \u0444\u0430\u0439\u043B\u0430...
diff --git a/core/resources/l10n/messages_uk_UA.properties b/core/resources/l10n/messages_uk_UA.properties
index 5d7147134..a7fc899ed 100644
--- a/core/resources/l10n/messages_uk_UA.properties
+++ b/core/resources/l10n/messages_uk_UA.properties
@@ -779,13 +779,13 @@ ShockCordCfg.lbl.Shockcordlength = Shock cord length:
 
 ! RocketComponentConfig
 RocketCompCfg.lbl.Componentname = Component name:
-RocketCompCfg.ttip.Thecomponentname = The component name.
+RocketCompCfg.lbl.Componentname.ttip = The component name.
 RocketCompCfg.tab.Override = Override
-RocketCompCfg.tab.MassandCGoverride = Mass and CG override options
+RocketCompCfg.tab.Override.ttip = Mass and CG override options
 RocketCompCfg.tab.Figure = Figure
 RocketCompCfg.tab.Figstyleopt = Figure style options
 RocketCompCfg.tab.Comment = Comment
-RocketCompCfg.tab.Specifyacomment = Specify a comment for the component
+RocketCompCfg.tab.Comment.ttip = Specify a comment for the component
 RocketCompCfg.tab.Appearance                      = Appearance
 RocketCompCfg.lbl.Mass = Mass:
 RocketCompCfg.lbl.Componentmass = Component mass:
@@ -1812,8 +1812,8 @@ CustomFinImport.error.badimage = Could not deduce fin shape from image.
 CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
 
 
-PresetModel.lbl.select = Select preset
-PresetModel.lbl.database = From database...
+PresetModel.lbl.custompreset = Custom
+PresetModel.lbl.partsLib = Parts Library
 
 DecalModel.lbl.select = <none>
 DecalModel.lbl.choose = From file...
diff --git a/core/resources/l10n/messages_zh_CN.properties b/core/resources/l10n/messages_zh_CN.properties
index 9e9cfed05..e968675da 100644
--- a/core/resources/l10n/messages_zh_CN.properties
+++ b/core/resources/l10n/messages_zh_CN.properties
@@ -803,8 +803,8 @@ PreferencesDialog.languages.default  = \u7CFB\u7EDF\u9ED8\u8BA4
 PreferencesDialog.lbl.language       = \u754C\u9762\u8BED\u8A00: 
 PreferencesDialog.lbl.languageEffect = \u8BED\u8A00\u8BBE\u7F6E\u5C06\u5728OpenRocket\u91CD\u542F\u540E\u751F\u6548
 
-PresetModel.lbl.database = \u4ECE\u6570\u636E\u5E93...
-PresetModel.lbl.select   = \u9009\u62E9\u9884\u8BBE
+PresetModel.lbl.custompreset   = \u5b9a\u5236
+PresetModel.lbl.partsLib = \u96f6\u4ef6\u5e93
 
 PrintDialog.but.previewAndPrint  = \u9884\u89C8 & \u6253\u5370
 PrintDialog.checkbox.showByStage = \u6309\u7EA7\u663E\u793A
@@ -927,13 +927,13 @@ RocketCompCfg.tab.Appearance                      = \u5916\u89C2
 RocketCompCfg.tab.Comment                         = \u6CE8\u91CA
 RocketCompCfg.tab.Figstyleopt                     = \u6837\u5F0F\u9009\u9879
 RocketCompCfg.tab.Figure                          = \u6837\u5F0F
-RocketCompCfg.tab.MassandCGoverride               = \u8D28\u91CF\u53CA\u91CD\u5FC3\u9009\u9879
+RocketCompCfg.tab.Override.ttip               = \u8D28\u91CF\u53CA\u91CD\u5FC3\u9009\u9879
 RocketCompCfg.tab.Override                        = \u8986\u5199
-RocketCompCfg.tab.Specifyacomment                 = \u7EC4\u4EF6\u6CE8\u91CA
+RocketCompCfg.tab.Comment.ttip                 = \u7EC4\u4EF6\u6CE8\u91CA
 RocketCompCfg.title.Aftshoulder                   = \u524D\u8FDE\u63A5\u5904
 RocketCompCfg.title.Noseconeshoulder              = \u5934\u9525\u8FDE\u63A5\u5904
 RocketCompCfg.ttip.Endcapped                      = \u8FDE\u63A5\u5904\u7EC8\u7AEF\u662F\u5426\u6709\u76D6.
-RocketCompCfg.ttip.Thecomponentname               = \u7EC4\u4EF6\u540D\u79F0.
+RocketCompCfg.lbl.Componentname.ttip               = \u7EC4\u4EF6\u540D\u79F0.
 
 RocketComponent.Position.ABSOLUTE = \u5934\u9525\u5C16\u7AEF
 RocketComponent.Position.AFTER    = \u7236\u7EC4\u4EF6\u4E4B\u540E
diff --git a/core/src/net/sf/openrocket/aerodynamics/AerodynamicCalculator.java b/core/src/net/sf/openrocket/aerodynamics/AerodynamicCalculator.java
index d51448699..fbdac87e4 100644
--- a/core/src/net/sf/openrocket/aerodynamics/AerodynamicCalculator.java
+++ b/core/src/net/sf/openrocket/aerodynamics/AerodynamicCalculator.java
@@ -68,5 +68,5 @@ public interface AerodynamicCalculator extends Monitorable {
 	 */
 	public AerodynamicCalculator newInstance();
 		
-	public boolean isContinuous( final Rocket rkt);
+	public boolean isContinuous(FlightConfiguration configuration, final Rocket rkt);
 }
diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java
index b1d2f3bfc..add6b3b7b 100644
--- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java
+++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java
@@ -4,6 +4,7 @@ import static net.sf.openrocket.util.MathUtil.pow2;
 
 import java.util.*;
 
+import net.sf.openrocket.rocketcomponent.AxialStage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,7 +81,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 		Map<RocketComponent, AerodynamicForces> assemblyMap = new LinkedHashMap<>();
 
 		// Calculate non-axial force data
-		calculateForceAnalysis(conditions, configuration.getRocket(), instMap, eachMap, assemblyMap, warnings);
+		calculateForceAnalysis(configuration, conditions, configuration.getRocket(), instMap, eachMap, assemblyMap, warnings);
 
 		// Calculate drag coefficient data
 		AerodynamicForces rocketForces = assemblyMap.get(configuration.getRocket());
@@ -125,7 +126,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 		return finalMap;
 	}
 
-	private AerodynamicForces calculateForceAnalysis(   FlightConditions conds,
+	private AerodynamicForces calculateForceAnalysis(   FlightConfiguration configuration,
+														FlightConditions conds,
 														RocketComponent comp,
 														InstanceMap instances,
 														Map<RocketComponent, AerodynamicForces> eachForces,
@@ -152,8 +154,12 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 		}
 
 		for( RocketComponent child : comp.getChildren()) {
+			// Ignore inactive stages
+			if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) {
+				continue;
+			}
 			// forces particular to each component
-			AerodynamicForces childForces = calculateForceAnalysis(conds, child, instances, eachForces, assemblyForces, warnings);
+			AerodynamicForces childForces = calculateForceAnalysis(configuration, conds, child, instances, eachForces, assemblyForces, warnings);
 
 			if(null != childForces) {
 				aggregateForces.merge(childForces);
@@ -240,7 +246,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 		if (calcMap == null)
 			buildCalcMap(configuration);
 		
-		if( ! isContinuous(  configuration.getRocket() ) ){
+		if (!isContinuous(configuration, configuration.getRocket())){
 			warnings.add( Warning.DIAMETER_DISCONTINUITY);
 		}
 		
@@ -266,20 +272,32 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 	}
 	
 	@Override
-	public boolean isContinuous( final Rocket rkt){
-		return testIsContinuous( rkt);
+	public boolean isContinuous(FlightConfiguration configuration, final Rocket rkt){
+		return testIsContinuous(configuration, rkt);
 	}
 	
-	private boolean testIsContinuous( final RocketComponent treeRoot ){
+	private boolean testIsContinuous(FlightConfiguration configuration, final RocketComponent treeRoot ){
 		Queue<RocketComponent> queue = new LinkedList<>();
-		queue.addAll(treeRoot.getChildren());
+		for (RocketComponent child : treeRoot.getChildren()) {
+			// Ignore inactive stages
+			if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) {
+				continue;
+			}
+			queue.add(child);
+		}
 		
 		boolean isContinuous = true;
 		SymmetricComponent prevComp = null; 
 		while((isContinuous)&&( null != queue.peek())){
 			RocketComponent comp = queue.poll();
 			if( comp instanceof SymmetricComponent ){
-				queue.addAll( comp.getChildren());
+				for (RocketComponent child : comp.getChildren()) {
+					// Ignore inactive stages
+					if (child instanceof AxialStage && !configuration.isStageActive(child.getStageNumber())) {
+						continue;
+					}
+					queue.add(child);
+				}
 				
 				SymmetricComponent sym = (SymmetricComponent) comp;
 				if( null == prevComp){
@@ -303,7 +321,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 						
 				prevComp = sym;
 			}else if( comp instanceof ComponentAssembly ){
-				isContinuous &= testIsContinuous( comp );
+				isContinuous &= testIsContinuous(configuration, comp);
 			}
 			
 		}
@@ -319,7 +337,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 	 * @param configuration		Rocket configuration
 	 * @param conditions		Flight conditions taken into account
 	 * @param map				?
-	 * @param set				Set to handle 
+	 * @param warningSet		Set to handle warnings
 	 * @return friction drag for entire rocket
 	 */
 	private double calculateFrictionCD(FlightConfiguration configuration, FlightConditions conditions,
@@ -611,7 +629,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 
 					double radius = 0;
 					final SymmetricComponent prevComponent = s.getPreviousSymmetricComponent();
-					if (prevComponent != null)
+					if (prevComponent != null && configuration.isComponentActive(prevComponent))
 						radius = prevComponent.getAftRadius();
 					
 					if (radius < s.getForeRadius()) {
@@ -672,7 +690,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
 				// its aft CD
 				double radius = 0;
 				final SymmetricComponent prevComponent = s.getPreviousSymmetricComponent();
-				if (prevComponent != null) {
+				if (prevComponent != null && configuration.isComponentActive(prevComponent)) {
 					radius = prevComponent.getAftRadius();
 				}
 				
diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java
index 50047e07f..3143eb83d 100644
--- a/core/src/net/sf/openrocket/document/Simulation.java
+++ b/core/src/net/sf/openrocket/document/Simulation.java
@@ -1,5 +1,6 @@
 package net.sf.openrocket.document;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.EventListener;
 import java.util.EventObject;
 import java.util.List;
@@ -350,13 +351,15 @@ public class Simulation implements ChangeSource, Cloneable {
 			SimulationEngine simulator;
 			
 			try {
-				simulator = simulationEngineClass.newInstance();
+				simulator = simulationEngineClass.getConstructor().newInstance();
 			} catch (InstantiationException e) {
 				throw new IllegalStateException("Cannot instantiate simulator.", e);
 			} catch (IllegalAccessException e) {
 				throw new IllegalStateException("Cannot access simulator instance?! BUG!", e);
+			} catch (InvocationTargetException | NoSuchMethodException e) {
+				throw new RuntimeException(e);
 			}
-			
+
 			SimulationConditions simulationConditions = options.toSimulationConditions();
 			simulationConditions.setSimulation(this);
 			for (SimulationListener l : additionalListeners) {
diff --git a/core/src/net/sf/openrocket/file/simplesax/SimpleSAX.java b/core/src/net/sf/openrocket/file/simplesax/SimpleSAX.java
index 2053d42e2..cc1fc55f6 100644
--- a/core/src/net/sf/openrocket/file/simplesax/SimpleSAX.java
+++ b/core/src/net/sf/openrocket/file/simplesax/SimpleSAX.java
@@ -11,6 +11,9 @@ import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.XMLReaderFactory;
 
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 
 /**
  * A "simple SAX" XML reader.  This system imposes the limit that an XML element may
@@ -18,27 +21,26 @@ import org.xml.sax.helpers.XMLReaderFactory;
  * both.  This holds true for both the OpenRocket and RockSim design formats and the
  * RockSim engine definition format.
  * <p>
- * The actual handling is performed by subclasses of {@link ElementHandler}.  The 
+ * The actual handling is performed by subclasses of {@link ElementHandler}.  The
  * initial handler is provided to the {@link #readXML(InputSource, ElementHandler, WarningSet)}
  * method.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public class SimpleSAX {
-
 	static final XMLReaderCache cache = new XMLReaderCache(10);
 
 	/**
 	 * Read a simple XML file.
-	 * 
+	 *
 	 * @param source			the SAX input source.
 	 * @param initialHandler	the initial content handler.
 	 * @param warnings			a warning set to store warning (cannot be <code>null</code>).
 	 * @throws IOException		if an I/O exception occurs while reading.
 	 * @throws SAXException		if e.g. malformed XML is encountered.
 	 */
-	public static void readXML(InputSource source, ElementHandler initialHandler,
-			WarningSet warnings) throws IOException, SAXException {
+	public static void readXML(InputSource source, ElementHandler initialHandler, WarningSet warnings)
+			throws IOException, SAXException {
 
 		DelegatorHandler xmlhandler = new DelegatorHandler(initialHandler, warnings);
 
@@ -55,17 +57,27 @@ public class SimpleSAX {
 	}
 
 	private static class XMLReaderCache {
+		private final SAXParserFactory parserFactory;
 
 		private final BlockingQueue<XMLReader> queue;
+
 		private XMLReaderCache( int maxSize ) {
-			this.queue = new LinkedBlockingQueue<XMLReader>(maxSize);
+			parserFactory = SAXParserFactory.newInstance();
+			parserFactory.setNamespaceAware(true);
+			queue = new LinkedBlockingQueue<XMLReader>(maxSize);
 		}
 
 		private XMLReader createXMLReader() throws SAXException {
-
 			XMLReader reader = queue.poll();
 			if ( reader == null ) {
+				try {
 				reader = XMLReaderFactory.createXMLReader();
+					SAXParser parser = parserFactory.newSAXParser();
+					reader = parser.getXMLReader();
+				}
+				catch (ParserConfigurationException ignore) {
+					System.out.print(ignore);
+				}
 			}
 			return reader;
 		}
@@ -77,5 +89,4 @@ public class SimpleSAX {
 			queue.offer( reader );
 		}
 	}
-
 }
diff --git a/core/src/net/sf/openrocket/masscalc/MassCalculator.java b/core/src/net/sf/openrocket/masscalc/MassCalculator.java
index 463ed7f4b..4b36d03dc 100644
--- a/core/src/net/sf/openrocket/masscalc/MassCalculator.java
+++ b/core/src/net/sf/openrocket/masscalc/MassCalculator.java
@@ -104,7 +104,7 @@ public class MassCalculator implements Monitorable {
 	public static RigidBody calculate( final MassCalculation.Type _type, final SimulationStatus status ){
 		final FlightConfiguration config = status.getConfiguration();
 		final double time = status.getSimulationTime();
-		final Collection<MotorClusterState> activeMotorList = status.getMotors();
+		final Collection<MotorClusterState> activeMotorList = status.getActiveMotors();
 		MassCalculation calculation= new MassCalculation( _type, config, time, activeMotorList, config.getRocket(), Transformation.IDENTITY, null);
 		
 		calculation.calculateAssembly();
diff --git a/core/src/net/sf/openrocket/motor/IgnitionEvent.java b/core/src/net/sf/openrocket/motor/IgnitionEvent.java
index 60a2bf2ea..619642167 100644
--- a/core/src/net/sf/openrocket/motor/IgnitionEvent.java
+++ b/core/src/net/sf/openrocket/motor/IgnitionEvent.java
@@ -4,6 +4,7 @@ import java.util.Locale;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.rocketcomponent.AxialStage;
+import net.sf.openrocket.rocketcomponent.FlightConfiguration;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.startup.Application;
@@ -13,25 +14,25 @@ public enum IgnitionEvent {
 	//// Automatic (launch or ejection charge)
 	AUTOMATIC( "AUTOMATIC", "MotorMount.IgnitionEvent.AUTOMATIC"){
 		@Override
-		public boolean isActivationEvent(FlightEvent testEvent, RocketComponent targetComponent) {
+		public boolean isActivationEvent(FlightConfiguration config, FlightEvent testEvent, RocketComponent targetComponent) {
 			AxialStage targetStage = targetComponent.getStage();
 			
-	        if ( targetStage.isLaunchStage() ){
-	        	return LAUNCH.isActivationEvent(testEvent, targetComponent);
+	        if (targetStage.isLaunchStage(config)) {
+	        	return LAUNCH.isActivationEvent(config, testEvent, targetComponent);
 	        } else {
-				return EJECTION_CHARGE.isActivationEvent(testEvent, targetComponent);
+				return EJECTION_CHARGE.isActivationEvent(config, testEvent, targetComponent);
 			}
 		}
 	},
 	LAUNCH ( "LAUNCH", "MotorMount.IgnitionEvent.LAUNCH"){
 		@Override
-		public boolean isActivationEvent( FlightEvent fe, RocketComponent source){
+		public boolean isActivationEvent(FlightConfiguration config,  FlightEvent fe, RocketComponent source){
 			return (fe.getType() == FlightEvent.Type.LAUNCH);
 		}
 	},
 	EJECTION_CHARGE ("EJECTION_CHARGE", "MotorMount.IgnitionEvent.EJECTION_CHARGE"){
 		@Override
-		public boolean isActivationEvent( FlightEvent testEvent, RocketComponent targetComponent){
+		public boolean isActivationEvent(FlightConfiguration config,  FlightEvent testEvent, RocketComponent targetComponent){
 			if (testEvent.getType() != FlightEvent.Type.EJECTION_CHARGE){
 				return false;
 			}
@@ -44,7 +45,7 @@ public enum IgnitionEvent {
 	},
 	BURNOUT ("BURNOUT", "MotorMount.IgnitionEvent.BURNOUT"){
 		@Override
-		public boolean isActivationEvent( FlightEvent testEvent, RocketComponent targetComponent){
+		public boolean isActivationEvent(FlightConfiguration config,  FlightEvent testEvent, RocketComponent targetComponent){
 			if (testEvent.getType() != FlightEvent.Type.BURNOUT)
 				return false;
 			
@@ -64,7 +65,7 @@ public enum IgnitionEvent {
 
 	//public static final IgnitionEvent[] events = {AUTOMATIC, LAUNCH, EJECTION_CHARGE, BURNOUT, NEVER};
 	
-	public boolean isActivationEvent( FlightEvent fe, RocketComponent source){
+	public boolean isActivationEvent(FlightConfiguration config,  FlightEvent fe, RocketComponent source){
 		// default behavior. Also for the NEVER case. 
 		return false;
 	}		
diff --git a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java
index 20f3a13f5..8e0f533c5 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java
@@ -67,6 +67,23 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
 	public boolean isCompatible(Class<? extends RocketComponent> type) {
 		 return BodyComponent.class.isAssignableFrom(type);
 	}
+
+	/**
+	 * Returns whether the current stage is active in the currently selected configuration.
+	 * @return true if the stage is active, false if not
+	 */
+	public boolean isStageActive() {
+		return getRocket().getSelectedConfiguration().isStageActive(getStageNumber());
+	}
+
+	/**
+	 * Returns whether the current stage is active in the flight configuration.
+	 * @param fc the flight configuration to check
+	 * @return true if the stage is active, false if not
+	 */
+	public boolean isStageActive(FlightConfiguration fc) {
+		return fc.isStageActive(getStageNumber());
+	}
 	
 	@Override
 	public void copyFlightConfiguration(FlightConfigurationId oldConfigId, FlightConfigurationId newConfigId) {
@@ -113,11 +130,11 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
 
 	/**
 	 * returns if the object is a launch stage
+	 * @param config the flight configuration which will check which stages are active
 	 * @return	if the object is a launch stage
 	 */
-	public boolean isLaunchStage(){
-		return ( this instanceof ParallelStage )
-				||( getRocket().getBottomCoreStage().equals(this));
+	public boolean isLaunchStage(FlightConfiguration config) {
+		return (getRocket().getBottomCoreStage(config).equals(this));
 	}
 
 	/**
diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java
index 2ae0211fa..7bb3cfae3 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java
@@ -60,8 +60,8 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
 	}
 	
 	/* Cached data */
-	final protected HashMap<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>();
-	final protected HashMap<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
+	final protected Map<Integer, StageFlags> stages = new HashMap<Integer, StageFlags>();	// Map of stage number to StageFlags of the corresponding stage
+	final protected Map<MotorConfigurationId, MotorConfiguration> motors = new HashMap<MotorConfigurationId, MotorConfiguration>();
 	final private Collection<MotorConfiguration> activeMotors = new ArrayList<MotorConfiguration>();
 	final private InstanceMap activeInstances = new InstanceMap();
 	
@@ -179,31 +179,52 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
 	 */
 	public void setOnlyStage(final int stageNumber) {
 		_setAllStages(false);
-		_setStageActive(stageNumber, true);
+		_setStageActive(stageNumber, true, false);
 		updateMotors();
 		updateActiveInstances();
 	}
-	
-	/** 
+
+	/**
 	 * This method flags the specified stage as requested.  Other stages are unaffected.
-	 * 
+	 *
 	 * @param stageNumber   stage number to flag
 	 * @param _active       inactive (<code>false</code>) or active (<code>true</code>)
+	 * @param activateSubStages whether the sub-stages of the specified stage should be activated as well.
 	 */
-	private void _setStageActive(final int stageNumber, final boolean _active ) {
+	public void _setStageActive(final int stageNumber, final boolean _active, final boolean activateSubStages) {
 		if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) {
 			stages.get(stageNumber).active = _active;
+			if (activateSubStages) {
+				// Set the active state of all the sub-stages as well.
+				for (AxialStage stage : rocket.getStage(stageNumber).getSubStages()) {
+					stages.get(stage.getStageNumber()).active = _active;
+				}
+			}
 			fireChangeEvent();
 			return;
 		}
 		log.error("error: attempt to retrieve via a bad stage number: " + stageNumber);
 	}
 	
+	/** 
+	 * This method flags the specified stage as requested.  Actives the sub-stages of the specified stage as well.
+	 * 
+	 * @param stageNumber   stage number to flag
+	 * @param _active       inactive (<code>false</code>) or active (<code>true</code>)
+	 */
+	public void _setStageActive(final int stageNumber, final boolean _active ) {
+		_setStageActive(stageNumber, _active, true);
+	}
+	
 	
 	public void toggleStage(final int stageNumber) {
 		if ((0 <= stageNumber) && (stages.containsKey(stageNumber))) {
 			StageFlags flags = stages.get(stageNumber);
 			flags.active = !flags.active;
+			// Set the active state of all the sub-stages as well.
+			for (AxialStage stage : rocket.getStage(stageNumber).getSubStages()) {
+				stages.get(stage.getStageNumber()).active = flags.active;
+			}
 			updateMotors();
 			updateActiveInstances();
 			
@@ -338,6 +359,18 @@ public class FlightConfiguration implements FlightConfigurableParameter<FlightCo
 
 		return results;
 	}
+
+	/**
+	 * Return all the stages in this configuration.
+	 * @return all the stages in this configuration.
+	 */
+	public List<AxialStage> getAllStages() {
+		List<AxialStage> stages = new ArrayList<>();
+		for (StageFlags flags : this.stages.values()) {
+			stages.add( rocket.getStage(flags.stageNumber));
+		}
+		return stages;
+	}
 	
 	public List<AxialStage> getActiveStages() {
 		List<AxialStage> activeStages = new ArrayList<>();
diff --git a/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java b/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java
index a1935c0cf..272de11ac 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/InnerTube.java
@@ -26,7 +26,7 @@ import net.sf.openrocket.util.MathUtil;
  *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
-public class InnerTube extends ThicknessRingComponent implements AxialPositionable, BoxBounded, Clusterable, RadialParent, MotorMount {
+public class InnerTube extends ThicknessRingComponent implements AxialPositionable, BoxBounded, Clusterable, RadialParent, MotorMount, InsideColorComponent {
 	private static final Translator trans = Application.getTranslator();
 	private static final Logger log = LoggerFactory.getLogger(InnerTube.class);
 	
@@ -37,6 +37,8 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab
 	private double overhang = 0;
 	private boolean isActingMount;
 	private MotorConfigurationSet motors;
+
+	private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
 	
 	/**
 	 * Main constructor.
@@ -447,6 +449,16 @@ public class InnerTube extends ThicknessRingComponent implements AxialPositionab
 		return this.motors.toDebug();
 	}
 
+	@Override
+	public InsideColorComponentHandler getInsideColorComponentHandler() {
+		return this.insideColorComponentHandler;
+	}
+
+	@Override
+	public void setInsideColorComponentHandler(InsideColorComponentHandler handler) {
+		this.insideColorComponentHandler = handler;
+	}
+
 	@Override
 	public boolean addConfigListener(RocketComponent listener) {
 		boolean success = super.addConfigListener(listener);
diff --git a/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java b/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java
index 8f74ee6fa..d09b71f54 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java
@@ -111,8 +111,8 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo
 	}
 	
 	@Override
-	public boolean isLaunchStage(){
-		return true;
+	public boolean isLaunchStage(FlightConfiguration config) {
+		return config.isStageActive(this.stageNumber);
 	}
 
 	@Override 
diff --git a/core/src/net/sf/openrocket/rocketcomponent/Rocket.java b/core/src/net/sf/openrocket/rocketcomponent/Rocket.java
index 7a3f1780a..37d245772 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/Rocket.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/Rocket.java
@@ -197,24 +197,37 @@ public class Rocket extends ComponentAssembly {
 	public AxialStage getStage( final int stageNumber ) {
 		return this.stageMap.get( stageNumber);
 	}
-	
-	/*
-	 * Returns the stage at the top of the central stack
-	 * 
-	 * @Return a reference to the topmost stage
+
+	/**
+	 * Get the topmost stage, only taking into account active stages from the flight configuration.
+	 * @param config flight configuration dictating which stages are active
+	 * @return the topmost active stage, or null if there are no active stages.
 	 */
-	public AxialStage getTopmostStage(){
-		return (AxialStage) getChild(0);
+	public AxialStage getTopmostStage(FlightConfiguration config) {
+		if (config == null) return null;
+
+		for (int i = 0; i < getChildCount(); i++) {
+			if (getChild(i) instanceof AxialStage && config.isStageActive(getChild(i).getStageNumber())) {
+				return (AxialStage) getChild(i);
+			}
+		}
+		return null;
 	}
-	
-	/*
-	 * Returns the stage at the top of the central stack
-	 * 
-	 * @Return a reference to the topmost stage
+
+	/**
+	 * Get the bottommost stage, only taking into account active stages from the flight configuration.
+	 * @param config flight configuration dictating which stages are active
+	 * @return the bottommost active stage, or null if there are no active stages.
 	 */
-	/*package-local*/ AxialStage getBottomCoreStage(){
-		// get last stage that's a direct child of the rocket.
-		return (AxialStage) children.get( children.size()-1 );
+	public AxialStage getBottomCoreStage(FlightConfiguration config) {
+		if (config == null) return null;
+
+		for (int i = getChildCount() - 1; i >= 0; i--) {
+			if (getChild(i) instanceof AxialStage && config.isStageActive(getChild(i).getStageNumber())) {
+				return (AxialStage) getChild(i);
+			}
+		}
+		return null;
 	}
 	
 	@Override
@@ -274,6 +287,11 @@ public class Rocket extends ComponentAssembly {
 		refType = type;
 		fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
 	}
+
+	@Override
+	public double getLength() {
+		return selectedConfiguration.getLength();
+	}
 	
 	
 	public double getCustomReferenceLength() {
@@ -291,6 +309,17 @@ public class Rocket extends ComponentAssembly {
 			fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
 		}
 	}
+
+	@Override
+	public double getBoundingRadius() {
+		double bounding = 0;
+		for (RocketComponent comp : children) {
+			if (comp instanceof ComponentAssembly) {
+				bounding = Math.max(bounding, ((ComponentAssembly) comp).getBoundingRadius());
+			}
+		}
+		return bounding;
+	}
 	
 	
 	
@@ -390,10 +419,12 @@ public class Rocket extends ComponentAssembly {
 		this.stageMap = r.stageMap;		
 
 		// these flight configurations need to reference the _this_ Rocket:
+		this.configSet.reset();
 		this.configSet.setDefault(new FlightConfiguration(this));
 		for (FlightConfigurationId key : r.configSet.map.keySet()) {
 			this.configSet.set(key, new FlightConfiguration(this, key));
 		}
+		this.selectedConfiguration = this.configSet.get(r.getSelectedConfiguration().getId());
 
 		this.perfectFinish = r.perfectFinish;
 		
@@ -735,6 +766,14 @@ public class Rocket extends ComponentAssembly {
         fireComponentChangeEvent(ComponentChangeEvent.TREE_CHANGE);
         return nextConfig.getFlightConfigurationID();
 	}
+
+	/**
+	 * Return all the flight configurations of this rocket.
+	 * @return all the flight configurations of this rocket.
+	 */
+	public FlightConfigurableParameterSet<FlightConfiguration> getFlightConfigurations() {
+		return this.configSet;
+	}
 	
 	
 	/**
diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
index 076211716..637d01465 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
@@ -1010,7 +1010,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
 	 * If the length of a component is settable, the class must define the setter method
 	 * itself.
 	 */
-	public final double getLength() {
+	public double getLength() {
 		mutex.verify();
 		return length;
 	}
@@ -1545,6 +1545,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
 				AxialStage stage = (AxialStage) component;
 				this.getRocket().forgetStage(stage);
 			}
+
+			// Remove sub-stages of the removed component
+			for (AxialStage stage : component.getSubStages()) {
+				this.getRocket().forgetStage(stage);
+			}
 			
 			this.checkComponentStructure();
 			component.checkComponentStructure();
@@ -1749,6 +1754,21 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
 		}
 		throw new IllegalStateException("getStage() called on hierarchy without an AxialStage.");
 	}
+
+	/**
+	 * Returns all the stages that are a child or sub-child of this component.
+	 * @return all the stages that are a child or sub-child of this component.
+	 */
+	public final List<AxialStage> getSubStages() {
+		List<AxialStage> result = new LinkedList<>();
+		Iterator<RocketComponent> it = iterator(false);
+		while (it.hasNext()) {
+			RocketComponent c = it.next();
+			if (c instanceof AxialStage)
+				result.add((AxialStage) c);
+		}
+		return result;
+	}
 	
 	/**
 	 * Return the first component assembly component that this component belongs to.
diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
index 8fdae800a..1d5b62e76 100644
--- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
+++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
@@ -45,7 +45,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
 	private final static double AOA_TUMBLE_CONDITION = Math.PI / 9.0;
 	
 	// The thrust must be below this value for the transition to tumbling.
-	// TODO: this is an arbitrary value
+	// TODO HIGH: this is an arbitrary value
 	private final static double THRUST_TUMBLE_CONDITION = 0.01;
 	
 	private SimulationStepper currentStepper;
@@ -65,7 +65,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
 		
 		// Set up rocket configuration
 		this.fcid = simulationConditions.getFlightConfigurationID();
-		FlightConfiguration simulationConfig = simulationConditions.getRocket().getFlightConfiguration( this.fcid).clone();
+		FlightConfiguration origConfig = simulationConditions.getRocket().getFlightConfiguration(this.fcid);
+		FlightConfiguration simulationConfig = origConfig.clone();
+		simulationConfig.copyStages(origConfig);	// Clone the stage activation configuration
 		if ( ! simulationConfig.hasMotors() ) {
 			throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
 		}
@@ -74,7 +76,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
 		currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
 		{
 			// main simulation branch 
-			final String branchName = simulationConfig.getRocket().getTopmostStage().getName();
+			final String branchName = simulationConfig.getRocket().getTopmostStage(currentStatus.getConfiguration()).getName();
 			currentStatus.setFlightData(new FlightDataBranch( branchName, FlightDataType.TYPE_TIME));
 		}
 		toSimulate.push(currentStatus);
@@ -273,9 +275,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
 			
 			// Check for motor ignition events, add ignition events to queue
 			for (MotorClusterState state : currentStatus.getActiveMotors() ){
-				if( state.testForIgnition(event )){
-					final double simulationTime = currentStatus.getSimulationTime() ;
-
+				if (state.testForIgnition(currentStatus.getConfiguration(), event)) {
 					MotorClusterState sourceState = (MotorClusterState) event.getData();
 					double ignitionDelay = 0;
 					if (event.getType() == FlightEvent.Type.BURNOUT)
@@ -543,7 +543,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
 			
 		}
 
-		// TODO : FUTURE : do not hard code the 1200 (maybe even make it configurable by the user)
+		// TODO FUTURE : do not hard code the 1200 (maybe even make it configurable by the user)
 		if( 1200 < currentStatus.getSimulationTime() ){
 			ret = false;
 			log.error("Simulation hit max time (1200s): aborting.");
@@ -553,6 +553,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
 		
 		// If no motor has ignited, abort
 		if (!currentStatus.isMotorIgnited()) {
+			// TODO MEDIUM: display this as a warning to the user (e.g. highlight the cell in the simulation panel in red and a hover: 'make sure the motor ignition is correct' or something)
 			throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noIgnition"));
 		}
 		
diff --git a/core/src/net/sf/openrocket/simulation/FlightEvent.java b/core/src/net/sf/openrocket/simulation/FlightEvent.java
index 55ceaab36..b78ad1f3b 100644
--- a/core/src/net/sf/openrocket/simulation/FlightEvent.java
+++ b/core/src/net/sf/openrocket/simulation/FlightEvent.java
@@ -172,7 +172,7 @@ public class FlightEvent implements Comparable<FlightEvent> {
 	 * @return
 	 */
 	public void validate(){
-		if( this.time == Double.NaN ){
+		if(Double.isNaN(this.time)){
 			throw new IllegalStateException(type.name()+" event has a NaN time!");
 		}
 		switch( this.type ){
diff --git a/core/src/net/sf/openrocket/simulation/MotorClusterState.java b/core/src/net/sf/openrocket/simulation/MotorClusterState.java
index 43c73f9c3..728287c96 100644
--- a/core/src/net/sf/openrocket/simulation/MotorClusterState.java
+++ b/core/src/net/sf/openrocket/simulation/MotorClusterState.java
@@ -4,6 +4,7 @@ import net.sf.openrocket.motor.IgnitionEvent;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.MotorConfiguration;
 import net.sf.openrocket.motor.MotorConfigurationId;
+import net.sf.openrocket.rocketcomponent.FlightConfiguration;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 
@@ -121,8 +122,8 @@ public class MotorClusterState {
 	/**
 	 * Compute the average thrust over an interval.
 	 * 
-	 * @param simulationTime
-	 * @param cond
+	 * @param startSimulationTime start time of the averaging interval
+	 * @param endSimulationTime end time of the averaging interval
 	 * @return
 	 */
 	public double getAverageThrust( final double startSimulationTime, final double endSimulationTime) {
@@ -141,7 +142,6 @@ public class MotorClusterState {
 	 * Compute the average thrust over an interval.
 	 * 
 	 * @param simulationTime
-	 * @param cond
 	 * @return
 	 */
 	public double getThrust( final double simulationTime){
@@ -182,9 +182,9 @@ public class MotorClusterState {
 		currentState = ThrustState.ARMED;
 	}
 	
-	public boolean testForIgnition( final FlightEvent _event ){
+	public boolean testForIgnition(FlightConfiguration flightConfiguration, final FlightEvent _event ){
 		RocketComponent mount = (RocketComponent) this.getMount();
-		return getIgnitionEvent().isActivationEvent( _event, mount);
+		return getIgnitionEvent().isActivationEvent(flightConfiguration, _event, mount);
 	}
 	
 	public String toDescription(){
diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java
index 64f1de5a0..3d750c651 100644
--- a/core/src/net/sf/openrocket/startup/Preferences.java
+++ b/core/src/net/sf/openrocket/startup/Preferences.java
@@ -68,6 +68,7 @@ public abstract class Preferences implements ChangeSource {
 	public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";
 	private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN";
 	private static final String OPEN_LEFTMOST_DESIGN_TAB = "OPEN_LEFTMOST_DESIGN_TAB";
+	private static final String SHOW_MARKERS = "SHOW_MARKERS";
 	private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING";
 	
 	//Preferences related to 3D graphics
@@ -469,7 +470,26 @@ public abstract class Preferences implements ChangeSource {
 	public final boolean isAlwaysOpenLeftmostTab() {
 		return this.getBoolean(OPEN_LEFTMOST_DESIGN_TAB, false);
 	}
-	
+
+	/**
+	 * Set whether pod set/booster markers should only be displayed when the pod set/booster is selected.
+	 * @param enabled 	true if pod set/booster markers should only be displayed when the pod set/booster is selected,
+	 * 					false if they should be displayed permanently.
+	 */
+	public final void setShowMarkers(boolean enabled) {
+		this.putBoolean(SHOW_MARKERS, enabled);
+	}
+
+	/**
+	 * Answer if pod set/booster markers should only be displayed when the pod set/booster is selected
+	 *
+	 * @return 	true if pod set/booster markers should only be displayed when the pod set/booster is selected,
+	 * 			false if they should be displayed permanently.
+	 */
+	public final boolean isShowMarkers() {
+		return this.getBoolean(SHOW_MARKERS, false);
+	}
+
 	/**
 	 * Return the OpenRocket unique ID.
 	 *
diff --git a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java
index 9f285a709..828a49447 100644
--- a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java
+++ b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java
@@ -267,22 +267,25 @@ public class BarrowmanCalculatorTest {
 	public void testContinuousRocket() {
 		Rocket rocket = TestRockets.makeEstesAlphaIII();
 		AerodynamicCalculator calc = new BarrowmanCalculator();
+		FlightConfiguration configuration = rocket.getSelectedConfiguration();
 		
-		assertTrue("Estes Alpha III should be continous: ", calc.isContinuous( rocket));
+		assertTrue("Estes Alpha III should be continous: ", calc.isContinuous(configuration, rocket));
 	}
 	
 	@Test
 	public void testContinuousRocketWithStrapOns() {
 		Rocket rocket = TestRockets.makeFalcon9Heavy();
 		AerodynamicCalculator calc = new BarrowmanCalculator();
+		FlightConfiguration configuration = rocket.getSelectedConfiguration();
 		
-		assertTrue("F9H should be continuous: ", calc.isContinuous( rocket));
+		assertTrue("F9H should be continuous: ", calc.isContinuous(configuration, rocket));
 	}
 	
 	@Test
 	public void testRadialDiscontinuousRocket() {
 		Rocket rocket = TestRockets.makeEstesAlphaIII();
 		AerodynamicCalculator calc = new BarrowmanCalculator();
+		FlightConfiguration configuration = rocket.getSelectedConfiguration();
 		
 		NoseCone nose = (NoseCone)rocket.getChild(0).getChild(0);
 		BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
@@ -291,13 +294,14 @@ public class BarrowmanCalculatorTest {
 		body.setOuterRadius( 0.012 );
 		body.setName( body.getName()+"  << discontinuous");
 		
-		assertFalse(" Estes Alpha III has an undetected discontinuity:", calc.isContinuous( rocket));
+		assertFalse(" Estes Alpha III has an undetected discontinuity:", calc.isContinuous(configuration, rocket));
 	}
 	
 	@Test
 	public void testRadialDiscontinuityWithStrapOns() {
 		Rocket rocket = TestRockets.makeFalcon9Heavy();
 		AerodynamicCalculator calc = new BarrowmanCalculator();
+		FlightConfiguration configuration = rocket.getSelectedConfiguration();
 		
 		final AxialStage coreStage = (AxialStage)rocket.getChild(1);
 		final ParallelStage booster = (ParallelStage)coreStage.getChild(0).getChild(0);
@@ -309,7 +313,7 @@ public class BarrowmanCalculatorTest {
 		body.setOuterRadius( 0.012 );
 		body.setName( body.getName()+"  << discontinuous");
 		
-		assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous( rocket));
+		assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous(configuration, rocket));
 	}
 
 	@Test
diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java
index c4ad802af..51db91e7d 100644
--- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java
+++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java
@@ -294,9 +294,22 @@ public class FlightConfigurationTest extends BaseTestCase {
 
 		config.toggleStage(0);
 		assertThat(" toggle stage #0: ", config.isStageActive(0), equalTo(false));
-		
-		AxialStage sustainer = rkt.getTopmostStage();
-		AxialStage booster = rkt.getBottomCoreStage();
+
+		AxialStage sustainer = rkt.getTopmostStage(config);
+		AxialStage booster = rkt.getBottomCoreStage(config);
+		assertThat(" sustainer stage is stage #1: ", sustainer.getStageNumber(), equalTo(1));
+		assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(1));
+
+		config.setAllStages();
+		config._setStageActive(1, false);
+		sustainer = rkt.getTopmostStage(config);
+		booster = rkt.getBottomCoreStage(config);
+		assertThat(" sustainer stage is stage #1: ", sustainer.getStageNumber(), equalTo(0));
+		assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(0));
+
+		config.setAllStages();
+		sustainer = rkt.getTopmostStage(config);
+		booster = rkt.getBottomCoreStage(config);
 		assertThat(" sustainer stage is stage #0: ", sustainer.getStageNumber(), equalTo(0));
 		assertThat(" booster stage is stage #1: ", booster.getStageNumber(), equalTo(1));
 		
@@ -351,7 +364,6 @@ public class FlightConfigurationTest extends BaseTestCase {
 
 		selected.clearAllStages();
 		selected.toggleStage(1);
-		selected.toggleStage(2);
 
 		// vvvv Test Target vvvv
 		InstanceMap instances = selected.getActiveInstances();
diff --git a/core/test/net/sf/openrocket/simulation/DisableStageTest.java b/core/test/net/sf/openrocket/simulation/DisableStageTest.java
new file mode 100644
index 000000000..9b4b0f7df
--- /dev/null
+++ b/core/test/net/sf/openrocket/simulation/DisableStageTest.java
@@ -0,0 +1,305 @@
+package net.sf.openrocket.simulation;
+
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.rocketcomponent.FlightConfiguration;
+import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.simulation.exception.MotorIgnitionException;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.simulation.listeners.SimulationListener;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+import net.sf.openrocket.util.TestRockets;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class that tests the effect on the simulation results of activating/deactivating stages.
+ *
+ * @author Sibo Van Gool <sibo.vangool@hotmail.com>
+ */
+public class DisableStageTest extends BaseTestCase {
+    /**
+     * Tests that the simulation results are correct when a single stage is deactivated and re-activated.
+     */
+    @Test
+    public void testSingleStage() throws SimulationException {
+        //// Test disabling the stage
+        Rocket rocket = TestRockets.makeEstesAlphaIII();
+
+        Simulation simDisabled = new Simulation(rocket);
+        simDisabled.setFlightConfigurationId(TestRockets.TEST_FCID_0);
+        simDisabled.getActiveConfiguration()._setStageActive(0, false);
+        simDisabled.getOptions().setISAAtmosphere(true);
+        simDisabled.getOptions().setTimeStep(0.05);
+
+        SimulationListener simulationListener = new AbstractSimulationListener();
+
+        // Since there are no stages, the simulation should throw an exception.
+        try {
+            simDisabled.simulate(simulationListener);
+        } catch (SimulationException e) {
+            if (!(e instanceof MotorIgnitionException)) {
+                Assert.fail("Simulation should have thrown a MotorIgnitionException");
+            }
+        }
+
+        //// Test re-enableing the stage.
+        Rocket rocketOriginal = TestRockets.makeEstesAlphaIII();
+
+        Simulation simOriginal = new Simulation(rocketOriginal);
+        simOriginal.setFlightConfigurationId(TestRockets.TEST_FCID_0);
+        simOriginal.getOptions().setISAAtmosphere(true);
+        simOriginal.getOptions().setTimeStep(0.05);
+
+        simDisabled.getActiveConfiguration().setAllStages();    // Re-enable all stages.
+
+        double delta = 0.05;    // 5 % error margin (simulations are not exact)
+        compareSims(simOriginal, simDisabled, simulationListener, delta);
+    }
+
+    /**
+     * Tests that the simulation results are correct when the last stage of a multi-stage rocket is deactivated and re-activated.
+     */
+    @Test
+    public void testMultiStageLastDisabled() {
+        //// Test disabling the stage
+        Rocket rocketRemoved = TestRockets.makeBeta();      // Rocket with the last stage removed
+        Rocket rocketDisabled = TestRockets.makeBeta();     // Rocket with the last stage disabled
+
+        int stageNr = rocketRemoved.getChildCount() - 1;
+        rocketRemoved.removeChild(stageNr);
+        FlightConfiguration fc = rocketDisabled.getFlightConfiguration(TestRockets.TEST_FCID_1);
+        fc._setStageActive(stageNr, false);
+
+        Simulation simRemoved = new Simulation(rocketRemoved);
+        simRemoved.setFlightConfigurationId(TestRockets.TEST_FCID_1);
+        simRemoved.getOptions().setISAAtmosphere(true);
+        simRemoved.getOptions().setTimeStep(0.05);
+
+        Simulation simDisabled = new Simulation(rocketDisabled);
+        simDisabled.setFlightConfigurationId(TestRockets.TEST_FCID_1);
+        simDisabled.getOptions().setISAAtmosphere(true);
+        simDisabled.getOptions().setTimeStep(0.05);
+
+        SimulationListener simulationListener = new AbstractSimulationListener();
+
+        double delta = 0.05;    // 5 % error margin (simulations are not exact)
+        compareSims(simRemoved, simDisabled, simulationListener, delta);
+
+        //// Test re-enableing the stage.
+        Rocket rocketOriginal = TestRockets.makeBeta();
+        Simulation simOriginal = new Simulation(rocketOriginal);
+        simOriginal.setFlightConfigurationId(TestRockets.TEST_FCID_1);
+        simOriginal.getOptions().setISAAtmosphere(true);
+        simOriginal.getOptions().setTimeStep(0.05);
+        
+        simDisabled.getActiveConfiguration().setAllStages();
+
+        compareSims(simOriginal, simDisabled, simulationListener, delta);
+    }
+
+    /**
+     * Tests that the simulation results are correct when the first stage of a multi-stage rocket is deactivated and re-activated.
+     */
+    // Don't even know if this test was useful, but simulation results vary wildly because the first stage is disabled,
+    // so I'm just gonna ignore this test.
+    /*@Test
+    public void testMultiStageFirstDisabled() {
+        //// Test disabling the stage
+        Rocket rocketRemoved = TestRockets.makeBeta();      // Rocket with the last stage removed
+        Rocket rocketDisabled = TestRockets.makeBeta();     // Rocket with the last stage disabled
+
+        // You need to disable the second stage body tube going into automatic radius mode, otherwise the
+        // removed and disabled rocket will have different results (removed rocket will have a different diameter)
+        BodyTube bodyTube = (BodyTube) rocketRemoved.getChild(1).getChild(0);
+        bodyTube.setOuterRadiusAutomatic(false);
+
+
+        int stageNr = 0;
+        rocketRemoved.removeChild(stageNr);
+        FlightConfiguration fc = rocketDisabled.getFlightConfiguration(TestRockets.TEST_FCID_1);
+        fc._setStageActive(stageNr, false);
+
+        Simulation simRemoved = new Simulation(rocketRemoved);
+        simRemoved.setFlightConfigurationId(TestRockets.TEST_FCID_1);
+        simRemoved.getOptions().setISAAtmosphere(true);
+        simRemoved.getOptions().setTimeStep(0.05);
+
+        Simulation simDisabled = new Simulation(rocketDisabled);
+        simDisabled.setFlightConfigurationId(TestRockets.TEST_FCID_1);
+        simDisabled.getOptions().setISAAtmosphere(true);
+        simDisabled.getOptions().setTimeStep(0.05);
+
+        SimulationListener simulationListener = new AbstractSimulationListener();
+
+        double delta = 0.1;    // 10 % error margin (simulations are very unstable and not exact when the first stage is disabled...)
+        compareSims(simRemoved, simDisabled, simulationListener, delta);
+
+        //// Test re-enableing the stage.
+        Rocket rocketOriginal = TestRockets.makeBeta();
+        Simulation simOriginal = new Simulation(rocketOriginal);
+        simOriginal.setFlightConfigurationId(TestRockets.TEST_FCID_1);
+        simOriginal.getOptions().setISAAtmosphere(true);
+        simOriginal.getOptions().setTimeStep(0.05);
+
+        simDisabled.getActiveConfiguration().setAllStages();
+
+        compareSims(simOriginal, simDisabled, simulationListener, delta);
+    }*/
+
+    /**
+     * Tests that the simulation results are correct when a booster stage is deactivated and re-activated.
+     */
+    @Test
+    public void testBooster1() {
+        //// Test disabling the stage
+        Rocket rocketRemoved = TestRockets.makeFalcon9Heavy();      // Rocket with the last stage removed
+        Rocket rocketDisabled = TestRockets.makeFalcon9Heavy();     // Rocket with the last stage disabled
+
+        FlightConfigurationId fcid =  new FlightConfigurationId(TestRockets.FALCON_9H_FCID_1);
+        int stageNr = 2;    // Stage 2 is the Parallel Booster Stage
+        rocketRemoved.getChild(1).getChild(0).removeChild(0);   // Remove the Parallel Booster Stage
+        FlightConfiguration fc = rocketDisabled.getFlightConfiguration(fcid);
+        fc._setStageActive(stageNr, false);
+
+        Simulation simRemoved = new Simulation(rocketRemoved);
+        simRemoved.setFlightConfigurationId(fcid);
+        simRemoved.getOptions().setISAAtmosphere(true);
+        simRemoved.getOptions().setTimeStep(0.05);
+
+        Simulation simDisabled = new Simulation(rocketDisabled);
+        simDisabled.setFlightConfigurationId(fcid);
+        simDisabled.getOptions().setISAAtmosphere(true);
+        simDisabled.getOptions().setTimeStep(0.05);
+
+        SimulationListener simulationListener = new AbstractSimulationListener();
+
+        double delta = 0.05;    // 5 % error margin (simulations are not exact)
+        compareSims(simRemoved, simDisabled, simulationListener, delta);
+
+        //// Test re-enableing the stage.
+        Rocket rocketOriginal = TestRockets.makeFalcon9Heavy();
+        Simulation simOriginal = new Simulation(rocketOriginal);
+        simOriginal.setFlightConfigurationId(fcid);
+        simOriginal.getOptions().setISAAtmosphere(true);
+        simOriginal.getOptions().setTimeStep(0.05);
+
+        simDisabled.getActiveConfiguration().setAllStages();
+
+        compareSims(simOriginal, simDisabled, simulationListener, delta);
+    }
+
+    /**
+     * Tests that the simulation results are correct when the parent stage of a booster stage is deactivated and re-activated.
+     */
+    @Test
+    public void testBooster2() {
+        //// Test disabling the stage
+        Rocket rocketRemoved = TestRockets.makeFalcon9Heavy();      // Rocket with the last stage removed
+        Rocket rocketDisabled = TestRockets.makeFalcon9Heavy();     // Rocket with the last stage disabled
+
+        FlightConfigurationId fid =  new FlightConfigurationId(TestRockets.FALCON_9H_FCID_1);
+        int stageNr = 1;    // Stage 1 is the Parallel Booster Stage's parent stage
+        rocketRemoved.getChild(1).removeChild(0);   // Remove the Parallel Booster Stage's parent stage
+        FlightConfiguration fc = rocketDisabled.getFlightConfiguration(fid);
+        fc._setStageActive(stageNr, false);
+
+        Simulation simRemoved = new Simulation(rocketRemoved);
+        simRemoved.setFlightConfigurationId(fid);
+        simRemoved.getOptions().setISAAtmosphere(true);
+        simRemoved.getOptions().setTimeStep(0.05);
+
+        Simulation simDisabled = new Simulation(rocketDisabled);
+        simDisabled.setFlightConfigurationId(fid);
+        simDisabled.getOptions().setISAAtmosphere(true);
+        simDisabled.getOptions().setTimeStep(0.05);
+
+        SimulationListener simulationListener = new AbstractSimulationListener();
+
+        // There should be no motors left at this point, so a no motors exception should be thrown
+        try {
+            simRemoved.simulate(simulationListener);
+        } catch (SimulationException e) {
+            if (!(e instanceof MotorIgnitionException)) {
+                Assert.fail("Simulation failed: " + e);
+            }
+        }
+
+        try {
+            simDisabled.simulate(simulationListener);
+        } catch (SimulationException e) {
+            if (!(e instanceof MotorIgnitionException)) {
+                Assert.fail("Simulation failed: " + e);
+            }
+        }
+
+        //// Test re-enableing the stage.
+        Rocket rocketOriginal = TestRockets.makeFalcon9Heavy();
+        Simulation simOriginal = new Simulation(rocketOriginal);
+        simOriginal.setFlightConfigurationId(fid);
+        simOriginal.getOptions().setISAAtmosphere(true);
+        simOriginal.getOptions().setTimeStep(0.05);
+
+        simDisabled.getActiveConfiguration().setAllStages();
+
+        double delta = 0.05;    // 5 % error margin (simulations are not exact)
+        compareSims(simOriginal, simDisabled, simulationListener, delta);
+    }
+
+    /**
+     * Compare simActual to simExpected and fail the unit test if there was an error during simulation or
+     * the two don't match.
+     * Tested parameters:
+     *  - maxAcceleration
+     *  - maxAltitude
+     *  - maxVelocity
+     *  - maxMachNumber
+     *  - flightTime
+     *  - launchRodVelocity
+     *  - deploymentVelocity
+     *  - groundHitVelocity
+     * @param simExpected the expected simulation results
+     * @param simActual the actual simulation results
+     * @param simulationListener the simulation listener to use for the comparison
+     * @param delta the error margin for the comparison (e.g. 0.05 = 5 % error margin)
+     */
+    private void compareSims(Simulation simExpected, Simulation simActual,
+                             SimulationListener simulationListener, double delta) {
+        try {
+            simExpected.simulate(simulationListener);
+            double maxAccelerationOriginal = simExpected.getSimulatedData().getMaxAcceleration();
+            double maxAltitudeOriginal = simExpected.getSimulatedData().getMaxAltitude();
+            double maxVelocityOriginal = simExpected.getSimulatedData().getMaxVelocity();
+            double maxMachNumberOriginal = simExpected.getSimulatedData().getMaxMachNumber();
+            double flightTimeOriginal = simExpected.getSimulatedData().getFlightTime();
+            double timeToApogeeOriginal = simExpected.getSimulatedData().getTimeToApogee();
+            double launchRodVelocityOriginal = simExpected.getSimulatedData().getLaunchRodVelocity();
+            double deploymentVelocityOriginal = simExpected.getSimulatedData().getDeploymentVelocity();
+            double groundHitVelocityOriginal = simExpected.getSimulatedData().getGroundHitVelocity();
+
+            simActual.simulate(simulationListener);
+            double maxAccelerationDisabled = simActual.getSimulatedData().getMaxAcceleration();
+            double maxAltitudeDisabled = simActual.getSimulatedData().getMaxAltitude();
+            double maxVelocityDisabled = simActual.getSimulatedData().getMaxVelocity();
+            double maxMachNumberDisabled = simActual.getSimulatedData().getMaxMachNumber();
+            double flightTimeDisabled = simActual.getSimulatedData().getFlightTime();
+            double timeToApogeeDisabled = simActual.getSimulatedData().getTimeToApogee();
+            double launchRodVelocityDisabled = simActual.getSimulatedData().getLaunchRodVelocity();
+            double deploymentVelocityDisabled = simActual.getSimulatedData().getDeploymentVelocity();
+            double groundHitVelocityDisabled = simActual.getSimulatedData().getGroundHitVelocity();
+
+            Assert.assertEquals(maxAccelerationOriginal, maxAccelerationDisabled, maxAccelerationOriginal * delta);
+            Assert.assertEquals(maxAltitudeOriginal, maxAltitudeDisabled, maxAltitudeOriginal * delta);
+            Assert.assertEquals(maxVelocityOriginal, maxVelocityDisabled, maxVelocityOriginal * delta);
+            Assert.assertEquals(maxMachNumberOriginal, maxMachNumberDisabled, maxMachNumberOriginal * delta);
+            Assert.assertEquals(flightTimeOriginal, flightTimeDisabled, flightTimeOriginal * delta);
+            Assert.assertEquals(timeToApogeeOriginal, timeToApogeeDisabled, timeToApogeeOriginal * delta);
+            Assert.assertEquals(launchRodVelocityOriginal, launchRodVelocityDisabled, launchRodVelocityOriginal * delta);
+            Assert.assertEquals(deploymentVelocityOriginal, deploymentVelocityDisabled, deploymentVelocityOriginal * delta);
+            Assert.assertEquals(groundHitVelocityOriginal, groundHitVelocityDisabled, groundHitVelocityOriginal * delta);
+        } catch (SimulationException e) {
+            Assert.fail("Simulation failed: " + e);
+        }
+    }
+}
diff --git a/swing/.classpath b/swing/.classpath
index 0a33deaf2..7daea48ea 100644
--- a/swing/.classpath
+++ b/swing/.classpath
@@ -17,6 +17,8 @@
 	<classpathentry kind="lib" path="/OpenRocket Core/lib/aopalliance.jar"/>
 	<classpathentry kind="lib" path="/OpenRocket Core/lib/commonmark-0.19.0.jar"/>
 	<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.inject.jar"/>
+	<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.json-1.1.3.jar"/>
+	<classpathentry kind="lib" path="/OpenRocket Core/lib/javax.json-api-1.1.3.jar"/>
 	<classpathentry kind="lib" path="/OpenRocket Core/resources"/>
 	<classpathentry kind="lib" path="resources"/>
 	<classpathentry kind="lib" path="lib/miglayout-4.0-swing.jar" sourcepath="reference/miglayout-4.0-sources.jar"/>
diff --git a/swing/build.xml b/swing/build.xml
index 6333164ad..578f0994c 100644
--- a/swing/build.xml
+++ b/swing/build.xml
@@ -154,7 +154,7 @@
 		depends="build">
 
 		<for param="vendor-dir">
-			<dirset dir="${resources-src.dir}/datafiles/rocksim_components"
+			<dirset dir="${resources-src.dir}/datafiles/rocksim_src"
 				includes="*"/>
 			<sequential>
 				<propertyregex property="vendor"
diff --git a/swing/src/net/sf/openrocket/gui/SpinnerEditor.java b/swing/src/net/sf/openrocket/gui/SpinnerEditor.java
index be4b79525..d02997e3d 100644
--- a/swing/src/net/sf/openrocket/gui/SpinnerEditor.java
+++ b/swing/src/net/sf/openrocket/gui/SpinnerEditor.java
@@ -1,8 +1,14 @@
 package net.sf.openrocket.gui;
 
 import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
 import javax.swing.text.DefaultFormatter;
 import javax.swing.text.DefaultFormatterFactory;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 
 /**
  * Editable editor for a JSpinner.  Simply uses JSpinner.DefaultEditor, which has been made
@@ -22,6 +28,59 @@ public class SpinnerEditor extends JSpinner.DefaultEditor {
 		DefaultFormatterFactory dff = (DefaultFormatterFactory) getTextField().getFormatterFactory();
 		DefaultFormatter formatter = (DefaultFormatter) dff.getDefaultFormatter();
 		formatter.setOverwriteMode(false);
+
+
+		// Add listeners to select all the text when the field is focussed
+		{
+			getTextField().addFocusListener(new FocusListener() {
+				@Override
+				public void focusGained(FocusEvent e) {
+					selectAllText();
+				}
+
+				@Override
+				public void focusLost(FocusEvent e) {
+				}
+			});
+
+			getTextField().addMouseListener(new MouseListener() {
+				private boolean isFocussed = false;    // Checks whether the text field was focussed when it was clicked upon
+
+				@Override
+				public void mouseClicked(MouseEvent e) {
+					// If the text field was focussed when it was clicked upon instead of e.g. tab-switching to gain focus,
+					// then the select all action from the focus listener is ignored (it is replaced by a cursor-click event).
+					// So if we detect such a focus change, then redo the select all action.
+					if (!isFocussed) {
+						SwingUtilities.invokeLater(new Runnable() {
+							@Override
+							public void run() {
+								JTextField tf = (JTextField) e.getSource();
+								tf.selectAll();
+							}
+						});
+					}
+				}
+
+				@Override
+				public void mousePressed(MouseEvent e) {
+					JTextField tf = (JTextField) e.getSource();
+					isFocussed = tf.hasFocus();
+				}
+
+				@Override
+				public void mouseReleased(MouseEvent e) {
+				}
+
+				@Override
+				public void mouseEntered(MouseEvent e) {
+				}
+
+				@Override
+				public void mouseExited(MouseEvent e) {
+				}
+			});
+		}
 	}
 
 	/**
@@ -33,5 +92,17 @@ public class SpinnerEditor extends JSpinner.DefaultEditor {
 		this(spinner);
 		getTextField().setColumns(cols);
 	}
+
+	/**
+	 * Highlights all the text in the text field.
+	 */
+	private void selectAllText() {
+		SwingUtilities.invokeLater(new Runnable() {
+			@Override
+			public void run() {
+				getTextField().selectAll();
+			}
+		});
+	}
 	
 }
diff --git a/swing/src/net/sf/openrocket/gui/adaptors/PresetModel.java b/swing/src/net/sf/openrocket/gui/adaptors/PresetModel.java
index 5fb2355d7..2fcec306e 100644
--- a/swing/src/net/sf/openrocket/gui/adaptors/PresetModel.java
+++ b/swing/src/net/sf/openrocket/gui/adaptors/PresetModel.java
@@ -5,16 +5,14 @@ import java.util.List;
 
 import javax.swing.AbstractListModel;
 import javax.swing.ComboBoxModel;
-import javax.swing.SwingUtilities;
 
-import net.sf.openrocket.database.ComponentPresetDatabase;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import net.sf.openrocket.gui.configdialog.RocketComponentConfig;
 import net.sf.openrocket.database.Database;
 import net.sf.openrocket.database.DatabaseListener;
 import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.gui.dialogs.preset.ComponentPresetChooserDialog;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.Markers;
 import net.sf.openrocket.preset.ComponentPreset;
@@ -29,8 +27,7 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
 	private static final Logger log = LoggerFactory.getLogger(PresetModel.class);
 	private static final Translator trans = Application.getTranslator();
 	
-	private static final String NONE_SELECTED = trans.get("lbl.select");
-	private static final String SELECT_DATABASE = trans.get("lbl.database");
+	private static final String NONE_SELECTED = String.format("<html><i>%s</i></html>", trans.get("PresetModel.lbl.custompreset"));
 	
 	private final Component parent;
 	private final RocketComponent component;
@@ -50,7 +47,7 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
 	
 	@Override
 	public int getSize() {
-		return presets.size() + 2;
+		return presets.size() + 1;
 	}
 	
 	@Override
@@ -58,9 +55,6 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
 		if (index == 0) {
 			return NONE_SELECTED;
 		}
-		if (index == getSize() - 1) {
-			return SELECT_DATABASE;
-		}
 		return presets.get(index - 1);
 	}
 	
@@ -72,24 +66,10 @@ public class PresetModel extends AbstractListModel implements ComboBoxModel, Com
 			throw new BugException("item is null");
 		} else if (item.equals(NONE_SELECTED)) {
 			component.clearPreset();
-		} else if (item.equals(SELECT_DATABASE)) {
-			SwingUtilities.invokeLater(new Runnable() {
-				@Override
-				public void run() {
-					((ComponentPresetDatabase) Application.getComponentPresetDao()).addDatabaseListener(PresetModel.this);
-					ComponentPresetChooserDialog dialog =
-							new ComponentPresetChooserDialog(SwingUtilities.getWindowAncestor(parent), component);
-					dialog.setVisible(true);
-					ComponentPreset preset = dialog.getSelectedComponentPreset();
-					if (preset != null) {
-						setSelectedItem(preset);
-					}
-					((ComponentPresetDatabase) Application.getComponentPresetDao()).removeChangeListener(PresetModel.this);
-				}
-			});
 		} else {
 			document.addUndoPosition("Use Preset " + component.getComponentName());
 			component.loadPreset((ComponentPreset) item);
+			((RocketComponentConfig) parent).setFocusElement();
 		}
 	}
 	
diff --git a/swing/src/net/sf/openrocket/gui/components/ConfigurationComboBox.java b/swing/src/net/sf/openrocket/gui/components/ConfigurationComboBox.java
index 4785570c2..43fc172a1 100644
--- a/swing/src/net/sf/openrocket/gui/components/ConfigurationComboBox.java
+++ b/swing/src/net/sf/openrocket/gui/components/ConfigurationComboBox.java
@@ -24,21 +24,49 @@ public class ConfigurationComboBox extends JComboBox<FlightConfiguration> implem
     public class ConfigurationModel implements MutableComboBoxModel<FlightConfiguration> {
 		
 		private final Rocket rkt;
-		
-		public ConfigurationModel(final Rocket _rkt) {
+		private FlightConfiguration selectedConfig;
+		private final boolean updateRocketConfig;
+		private final ConfigurationModel listener;
+
+		/**
+		 * @param _rkt the rocket to get the configurations from and to (optionally) change the rocket's selected configuration
+		 * @param _updateRocketConfig whether to update the rocket's selected configuration based on the selected combo box item,
+		 *                            or just change the combo box item without altering the rocket's configuration.
+		 * @param listener model that should change its selected item to this model's selected item
+		 */
+		public ConfigurationModel(final Rocket _rkt, boolean _updateRocketConfig, ConfigurationModel listener) {
 			this.rkt = _rkt;
+			this.updateRocketConfig = _updateRocketConfig;
+			this.selectedConfig = this.rkt.getSelectedConfiguration();
+			this.listener = listener;
+		}
+
+		public ConfigurationModel(final Rocket _rkt, boolean _updateRocketConfig) {
+			this(_rkt, _updateRocketConfig, null);
 		}
 		
 		@Override
 		public FlightConfiguration getSelectedItem() {
-			return rkt.getSelectedConfiguration();
+			if (updateRocketConfig) {
+				return rkt.getSelectedConfiguration();
+			} else {
+				return selectedConfig;
+			}
 		}
 		
 		@Override
 		public void setSelectedItem(Object nextItem) {
 			if( nextItem instanceof FlightConfiguration ){
 				FlightConfigurationId selectedId = ((FlightConfiguration)nextItem).getId();
-				rkt.setSelectedConfiguration(selectedId);
+				if (updateRocketConfig) {
+					rkt.setSelectedConfiguration(selectedId);
+				} else {
+					selectedConfig = rkt.getFlightConfiguration(selectedId);
+				}
+
+				if (listener != null) {
+					listener.setSelectedItem(nextItem);
+				}
 			}
 		}
 		
@@ -79,9 +107,15 @@ public class ConfigurationComboBox extends JComboBox<FlightConfiguration> implem
 	
     private final Rocket rkt;
 
-    public ConfigurationComboBox(Rocket _rkt) {
+	/**
+	 * @param _rkt the rocket to get the configurations from and to (optionally) change the rocket's selected configuration
+	 * @param _updateRocketConfig whether to update the rocket's selected configuration based on the selected combo box item,
+	 *                            or just change the combo box item without altering the rocket's configuration.
+	 */
+    public ConfigurationComboBox(Rocket _rkt, boolean _updateRocketConfig) {
 		rkt = _rkt;
-		setModel(new ConfigurationModel(rkt));
+		final ConfigurationModel model = new ConfigurationModel(rkt, _updateRocketConfig);
+		setModel(model);
 		rkt.addChangeListener(this);
 	
 		addPopupMenuListener(new PopupMenuListener() {
@@ -89,12 +123,18 @@ public class ConfigurationComboBox extends JComboBox<FlightConfiguration> implem
 			public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
 			
 			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
-			    setModel(new ConfigurationModel(rkt));		    
+				final ConfigurationModel model2 = new ConfigurationModel(rkt, _updateRocketConfig, model);
+				model2.setSelectedItem(model.getSelectedItem());
+			    setModel(model2);
 			}
 			
 		});
 	
     }
+
+	public ConfigurationComboBox(Rocket _rkt) {
+		this(_rkt, true);
+	}
     
     @Override
     public void stateChanged(EventObject e) {
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java
index 9ab43f596..39fbaa2ba 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java
@@ -6,6 +6,8 @@ import javax.swing.JDialog;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
@@ -23,6 +25,12 @@ import net.sf.openrocket.rocketcomponent.SymmetricComponent;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.Arrays;
+
 @SuppressWarnings("serial")
 public class BodyTubeConfig extends RocketComponentConfig {
 
@@ -43,6 +51,7 @@ public class BodyTubeConfig extends RocketComponentConfig {
 
 		JSpinner spin = new JSpinner(length.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel.add(spin, "growx");
 
 		panel.add(new UnitSelector(length), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java b/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
index 3566cf3e9..bd15b1b90 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java
@@ -1,18 +1,24 @@
 package net.sf.openrocket.gui.configdialog;
 
 
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
 import java.awt.Window;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.swing.JDialog;
 
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.main.BasicFrame;
 import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.gui.util.SwingPreferences;
+import net.sf.openrocket.gui.util.WindowLocationUtil;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.rocketcomponent.AxialStage;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@@ -230,8 +236,9 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 	 * @param document		the document to configure.
 	 * @param component		the component to configure.
 	 * @param rememberPreviousTab if true, the previous tab will be remembered and used for the new dialog
+	 * @param includeUndoModify	if true, include a 'Modify component' undo action
 	 */
-	public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab) {
+	public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab, boolean includeUndoModify) {
 		if (dialog != null) {
 			// Don't remember the previous tab for rockets or stages, because this will leave you in the override tab for
 			// the next component, which is generally not what you want.
@@ -256,15 +263,32 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis
 
 		dialog = new ComponentConfigDialog(parent, document, component);
 		dialog.setVisible(true);
+		if (parent instanceof BasicFrame && BasicFrame.getStartupFrame() == parent) {
+			WindowLocationUtil.moveIfOutsideOfParentMonitor(dialog, parent);
+		}
 
 		////Modify
-		if (component.getConfigListeners().size() == 0) {
-			document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
-		} else {
-			document.addUndoPosition(trans.get("ComponentCfgDlg.ModifyComponents"));
+		if (includeUndoModify) {
+			if (component.getConfigListeners().size() == 0) {
+				document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
+			} else {
+				document.addUndoPosition(trans.get("ComponentCfgDlg.ModifyComponents"));
+			}
 		}
 	}
 
+	/**
+	 * A singleton configuration dialog.  Will create and show a new dialog if one has not
+	 * previously been used, or update the dialog and show it if a previous one exists.
+	 *
+	 * @param document		the document to configure.
+	 * @param component		the component to configure.
+	 * @param rememberPreviousTab if true, the previous tab will be remembered and used for the new dialog
+	 */
+	public static void showDialog(Window parent, OpenRocketDocument document, RocketComponent component, boolean rememberPreviousTab) {
+		ComponentConfigDialog.showDialog(parent, document, component, rememberPreviousTab, true);
+	}
+
 	/**
 	 * A singleton configuration dialog.  Will create and show a new dialog if one has not
 	 * previously been used, or update the dialog and show it if a previous one exists.
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
index ba6b077da..b695e5dbf 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
@@ -81,6 +81,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
 	private Point dragPoint = null;
 
 	private FinPointFigure figure = null;
+	private ScaleScrollPane figurePane = null;
 	private ScaleSelector selector;
 	
 	public FreeformFinSetConfig(OpenRocketDocument d, RocketComponent component, JDialog parent) {
@@ -219,7 +220,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
 		
 		// Create the figure
 		figure = new FinPointFigure(finset);
-		ScaleScrollPane figurePane = new FinPointScrollPane( figure);
+		figurePane = new FinPointScrollPane( figure);
 		
 		// Create the table
 		tableModel = new FinPointTableModel();
@@ -392,9 +393,10 @@ public class FreeformFinSetConfig extends FinSetConfig {
 		    }
             figure.updateFigure();
 		}
-		
-		revalidate();
-		repaint();
+
+		if (figurePane != null) {
+			figurePane.revalidate();
+		}
 	}
 	
 	private class FinPointScrollPane extends ScaleScrollPane {
@@ -408,8 +410,6 @@ public class FreeformFinSetConfig extends FinSetConfig {
 
 		@Override
 		public void mousePressed(MouseEvent event) {
-			int mods = event.getModifiersEx();
-
 			final FreeformFinSet finset = (FreeformFinSet) component;
 
 			final int pressIndex = getPoint(event);
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
index e5595286f..3e3ddb3cb 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
@@ -64,7 +64,6 @@ public class InnerTubeConfig extends RocketComponentConfig {
 		super(d, c, parent);
 
 		//// General and General properties
-		JPanel rightPanel = new JPanel(new MigLayout());
 		JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
 
 		DoubleModel m;
@@ -86,7 +85,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
 		panel.add(spin, "growx");
 
 		panel.add(new UnitSelector(od), "growx");
-		panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap");
+		panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "wmin 100lp, growx, wrap");
 
 		if (od.isAutomaticAvailable()) {
 			JCheckBox check = new JCheckBox(od.getAutomaticAction());
@@ -106,7 +105,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
 		panel.add(spin, "growx");
 
 		panel.add(new UnitSelector(m), "growx");
-		panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "w 100lp, wrap");
+		panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "wmin 100lp, growx, wrap");
 
 		if (m.isAutomaticAvailable()) {
 			JCheckBox check = new JCheckBox(m.getAutomaticAction());
@@ -127,7 +126,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
 		panel.add(spin, "growx");
 
 		panel.add(new UnitSelector(m), "growx");
-		panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap");
+		panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "wmin 100lp, growx, wrap");
 
 
 		////  Inner tube length
@@ -138,14 +137,15 @@ public class InnerTubeConfig extends RocketComponentConfig {
 
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel.add(spin, "growx");
 
 		panel.add(new UnitSelector(m), "growx");
-		panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "w 100lp, wrap");
+		panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "wmin 100lp, growx, wrap");
 
 		//// Material
 		panel.add(materialPanel(Material.Type.BULK),
-				"spanx 3, growx, wrap 15lp");
+				"spanx 4, growx, wrap 15lp");
 
 
 		//// Right side of panel ----
@@ -174,7 +174,7 @@ public class InnerTubeConfig extends RocketComponentConfig {
 		panel2.add(new BasicSlider(m.getSliderModel(
 						new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE),
 						new DoubleModel(component.getParent(), "Length"))),
-				"w 100lp, wrap");
+				"wmin 100lp, growx, wrap");
 
 
 
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java
index eedab2730..8302641bb 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java
@@ -45,6 +45,7 @@ public class LaunchLugConfig extends RocketComponentConfig {
 		
 		JSpinner spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel.add(spin, "growx");
 		
 		panel.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java
index 5e7d185ec..23102e1f9 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java
@@ -138,6 +138,7 @@ public class MassComponentConfig extends RocketComponentConfig {
 		m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel2.add(spin, "growx");
 		
 		panel2.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java
index f63abcc16..38fdffc3b 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java
@@ -163,6 +163,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
 		m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel.add(spin, "growx");
 		
 		panel.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java
index 3edfa1e89..b5e005a4a 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RailButtonConfig.java
@@ -92,6 +92,7 @@ public class RailButtonConfig extends RocketComponentConfig {
 			DoubleModel offsetModel = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
 			JSpinner offsetSpinner = new JSpinner(offsetModel.getSpinnerModel());
 			offsetSpinner.setEditor(new SpinnerEditor(offsetSpinner));
+			focusElement = offsetSpinner;
 			panel.add(offsetSpinner, "growx");
 			panel.add(new UnitSelector(offsetModel), "growx");
 			panel.add(new BasicSlider(offsetModel.getSliderModel(
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
index f10ea3caa..27c2a4282 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
@@ -20,6 +20,7 @@ import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.EngineBlock;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.ThicknessRingComponent;
 import net.sf.openrocket.rocketcomponent.position.AxialMethod;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
@@ -116,6 +117,9 @@ public class RingComponentConfig extends RocketComponentConfig {
 			
 			spin = new JSpinner(m.getSpinnerModel());
 			spin.setEditor(new SpinnerEditor(spin));
+			if (component instanceof ThicknessRingComponent) {
+				focusElement = spin;
+			}
 			panel.add(spin, "growx");
 			
 			panel.add(new UnitSelector(m), "growx");
@@ -139,6 +143,9 @@ public class RingComponentConfig extends RocketComponentConfig {
 		m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		if (!(component instanceof ThicknessRingComponent)) {
+			focusElement = spin;
+		}
 		panel.add(spin, "growx");
 		
 		panel.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
index 976e2945a..59628c5ac 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
@@ -22,8 +22,10 @@ import javax.swing.JSpinner;
 import javax.swing.JTabbedPane;
 import javax.swing.JTextArea;
 import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ComponentPresetDatabase;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
@@ -36,6 +38,7 @@ import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.StyledLabel.Style;
 import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.dialogs.preset.ComponentPresetChooserDialog;
 import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.gui.widgets.SelectColorButton;
 import net.sf.openrocket.l10n.Translator;
@@ -61,6 +64,7 @@ public class RocketComponentConfig extends JPanel {
 	
 	private JComboBox<?> presetComboBox;
 	private PresetModel presetModel;
+	protected Component focusElement = null;	// Element that will be focused on after a preset is selected
 	
 	protected final JTextField componentNameField;
 	protected JTextArea commentTextArea;
@@ -100,7 +104,7 @@ public class RocketComponentConfig extends JPanel {
 		//// Component name:
 		JLabel label = new JLabel(trans.get("RocketCompCfg.lbl.Componentname"));
 		//// The component name.
-		label.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
+		label.setToolTipText(trans.get("RocketCompCfg.lbl.Componentname.ttip"));
 		this.add(label, "spanx, height 32!, split");
 
 		componentNameField = new JTextField(15);
@@ -108,15 +112,27 @@ public class RocketComponentConfig extends JPanel {
 		componentNameField.addActionListener(textFieldListener);
 		componentNameField.addFocusListener(textFieldListener);
 		//// The component name.
-		componentNameField.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
+		componentNameField.setToolTipText(trans.get("RocketCompCfg.lbl.Componentname.ttip"));
 		this.add(componentNameField, "growx");
 
 		if (allSameType && component.getPresetType() != null) {
 			// If the component supports a preset, show the preset selection box.
 			presetModel = new PresetModel(this, document, component);
 			presetComboBox = new JComboBox(presetModel);
+			presetComboBox.setMaximumRowCount(25);
 			presetComboBox.setEditable(false);
-			this.add(presetComboBox, "");
+			presetComboBox.setToolTipText(trans.get("PresetModel.combo.ttip"));
+			this.add(presetComboBox, "growx 110");
+
+			final JButton selectPreset = new SelectColorButton(trans.get("PresetModel.lbl.partsLib"));
+			selectPreset.setToolTipText(trans.get("PresetModel.lbl.partsLib.ttip"));
+			selectPreset.addActionListener(new ActionListener() {
+				@Override
+				public void actionPerformed(ActionEvent e) {
+					selectPreset();
+				}
+			});
+			this.add(selectPreset);
 		}
 
 		tabbedPane = new JTabbedPane();
@@ -124,17 +140,17 @@ public class RocketComponentConfig extends JPanel {
 
 		//// Override and Mass and CG override options
 		tabbedPane.addTab(trans.get("RocketCompCfg.tab.Override"), null, overrideTab(),
-				trans.get("RocketCompCfg.tab.MassandCGoverride"));
+				trans.get("RocketCompCfg.tab.Override.ttip"));
 		if (allMassive) {
 			//// Appearance options
 			appearancePanel = new AppearancePanel(document, component, parent);
 			tabbedPane.addTab(trans.get("RocketCompCfg.tab.Appearance"), null, appearancePanel,
-					"Appearance Tool Tip");
+					trans.get("RocketCompCfg.tab.Appearance.ttip"));
 		}
 
 		//// Comment and Specify a comment for the component
 		tabbedPane.addTab(trans.get("RocketCompCfg.tab.Comment"), null, commentTab(),
-				trans.get("RocketCompCfg.tab.Specifyacomment"));
+				trans.get("RocketCompCfg.tab.Comment.ttip"));
 
 		addButtons();
 
@@ -241,6 +257,24 @@ public class RocketComponentConfig extends JPanel {
 		}
 	}
 
+	private void selectPreset() {
+		SwingUtilities.invokeLater(new Runnable() {
+			@Override
+			public void run() {
+				if (presetComboBox == null || presetModel == null) return;
+				((ComponentPresetDatabase) Application.getComponentPresetDao()).addDatabaseListener(presetModel);
+				ComponentPresetChooserDialog dialog =
+						new ComponentPresetChooserDialog(SwingUtilities.getWindowAncestor(RocketComponentConfig.this), component);
+				dialog.setVisible(true);
+				ComponentPreset preset = dialog.getSelectedComponentPreset();
+				if (preset != null) {
+					presetModel.setSelectedItem(preset);
+				}
+				((ComponentPresetDatabase) Application.getComponentPresetDao()).removeChangeListener(presetModel);
+			}
+		});
+	}
+
 	public void clearConfigListeners() {
 		if (appearancePanel != null) {
 			appearancePanel.clearConfigListeners();
@@ -702,6 +736,24 @@ public class RocketComponentConfig extends JPanel {
 			}
 		}
 	}
+
+	/**
+	 * Requests focus for the focus element that should be active after a preset is selected.
+	 */
+	public void setFocusElement() {
+		if (focusElement != null) {
+			SwingUtilities.invokeLater(new Runnable() {
+				public void run() {
+					if (focusElement instanceof JSpinner) {
+						SpinnerEditor ed = (SpinnerEditor) ((JSpinner)focusElement).getEditor();
+						ed.getTextField().requestFocusInWindow();
+					} else {
+						focusElement.requestFocusInWindow();
+					}
+				}
+			});
+		}
+	}
 	
 	
 	protected void register(Invalidatable model) {
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java
index 624738a95..a7a6e8a78 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java
@@ -80,6 +80,7 @@ public class ShockCordConfig extends RocketComponentConfig {
 		m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel2.add(spin, "growx");
 		
 		panel2.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java
index c4f6e2d65..504c6e712 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java
@@ -149,6 +149,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
 		m = new DoubleModel(component, "AxialOffset", UnitGroup.UNITS_LENGTH);
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel.add(spin, "growx");
 		
 		panel.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java
index a005d11e2..e9de11352 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java
@@ -54,6 +54,7 @@ public class TubeFinSetConfig extends RocketComponentConfig {
 		
 		spin = new JSpinner(m.getSpinnerModel());
 		spin.setEditor(new SpinnerEditor(spin));
+		focusElement = spin;
 		panel.add(spin, "growx");
 		
 		panel.add(new UnitSelector(m), "growx");
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java
index ad53576e6..3a1db6af8 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/ScaleDialog.java
@@ -346,7 +346,7 @@ public class ScaleDialog extends JDialog {
 		panel.add(selectionOption, "growx, wrap para*2");
 
 		// Select the 'scale component / scale selection and all subcomponents' if a component is selected
-		if (selection != null && selection.size() > 0) {
+		if (options.size() > 1 && selection != null && selection.size() > 0) {
 			boolean entireRocket = false;	// Flag to scale entire rocket
 			for (RocketComponent component : selection) {
 				if (component instanceof Rocket || (component instanceof AxialStage && !(component instanceof ParallelStage))) {
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java
index 08ef4acb1..3a98bd616 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java
@@ -11,6 +11,7 @@ import javax.swing.JSpinner;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.main.BasicFrame;
 import net.sf.openrocket.startup.Preferences;
 import net.sf.openrocket.unit.UnitGroup;
 
@@ -93,7 +94,6 @@ public class DesignPreferencesPanel extends PreferencesPanel {
 		// // Always open leftmost tab when opening a component edit dialog
 		final JCheckBox alwaysOpenLeftmostTab = new JCheckBox(
 				trans.get("pref.dlg.checkbox.AlwaysOpenLeftmost"));
-
 		alwaysOpenLeftmostTab.setSelected(preferences.isAlwaysOpenLeftmostTab());
 		alwaysOpenLeftmostTab.setToolTipText(trans.get("pref.dlg.checkbox.AlwaysOpenLeftmost.ttip"));
 		alwaysOpenLeftmostTab.addActionListener(new ActionListener() {
@@ -103,7 +103,7 @@ public class DesignPreferencesPanel extends PreferencesPanel {
 						.isSelected());
 			}
 		});
-		this.add(alwaysOpenLeftmostTab, "wrap, growx, span 2");
+		this.add(alwaysOpenLeftmostTab, "wrap, growx, spanx");
 
 		// // Update flight estimates in the design window
 		final JCheckBox updateEstimates = new JCheckBox(
@@ -117,5 +117,23 @@ public class DesignPreferencesPanel extends PreferencesPanel {
 			}
 		});
 		this.add(updateEstimates, "wrap, growx, sg combos ");
+
+		// // Only show pod set/booster markers when they are selected
+		final JCheckBox showMarkers = new JCheckBox(
+				trans.get("pref.dlg.checkbox.Markers"));
+		showMarkers.setToolTipText(trans.get("pref.dlg.checkbox.Markers.ttip"));
+		showMarkers.setSelected(preferences.isShowMarkers());
+		showMarkers.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				preferences.setShowMarkers(showMarkers
+						.isSelected());
+				// Update all BasicFrame rocket panel figures because it can change due to the preference change
+				for (BasicFrame frame : BasicFrame.getAllFrames()) {
+					frame.getRocketPanel().updateFigures();
+				}
+			}
+		});
+		this.add(showMarkers, "wrap, growx, spanx");
 	}
 }
diff --git a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java
index b83143638..5c2d39c1e 100644
--- a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java
+++ b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java
@@ -7,6 +7,7 @@ import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
 import com.jogamp.opengl.glu.GLU;
 import com.jogamp.opengl.glu.GLUquadric;
 
+import net.sf.openrocket.rocketcomponent.InnerTube;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -98,6 +99,8 @@ public class ComponentRenderer {
 
 		if (c instanceof BodyTube) {
 			renderTube(gl, (BodyTube) c, which);
+		} else if (c instanceof InnerTube) {
+			renderTube(gl, (InnerTube) c, which);
 		} else if (c instanceof LaunchLug) {
 			renderLug(gl, (LaunchLug) c, which);
 		} else if ( c instanceof RailButton ){
@@ -257,6 +260,10 @@ public class ComponentRenderer {
 		renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength());
 	}
 
+	private void renderTube(GL2 gl, InnerTube t, Surface which) {
+		renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength());
+	}
+
 	private void renderRing(GL2 gl, RingComponent r) {
 
 		gl.glRotated(90, 0, 1.0, 0);
diff --git a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoFrame.java b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoFrame.java
index 2030dba2b..3ce2cd3cc 100644
--- a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoFrame.java
+++ b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoFrame.java
@@ -108,7 +108,7 @@ public class PhotoFrame extends JFrame {
 
 		settings = new JDialog(this, trans.get("PhotoSettingsConfig.title")) {
 			{
-				setContentPane(new PhotoSettingsConfig(p));
+				setContentPane(new PhotoSettingsConfig(p, document));
 				pack();
 				this.setLocationByPlatform(true);
 				GUIUtil.rememberWindowSize(this);
diff --git a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java
index eca18a495..23599f7f3 100644
--- a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java
+++ b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java
@@ -36,7 +36,7 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings
 	private double exhaustScale = 1.0;
 	private double flameAspectRatio = 1.0;
 	
-	private double sparkConcentration = 0;
+	private double sparkConcentration = 0.2;
 	private double sparkWeight = 0;
 	
 	private Sky sky = Mountains.instance;
@@ -278,5 +278,6 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings
 
 	public void setSmokeOpacity(double smokeOpacity) {
 		this.smokeOpacity = smokeOpacity;
+		setSmokeAlpha(smokeOpacity);
 	}
 }
\ No newline at end of file
diff --git a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettingsConfig.java b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettingsConfig.java
index 6294a6e96..ef27b0dc4 100644
--- a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettingsConfig.java
+++ b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettingsConfig.java
@@ -25,8 +25,10 @@ import javax.swing.event.ChangeListener;
 
 import com.jogamp.opengl.GL2;
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.ColorIcon;
 import net.sf.openrocket.gui.components.EditableSpinner;
 import net.sf.openrocket.gui.components.StyledLabel;
@@ -125,7 +127,7 @@ public class PhotoSettingsConfig extends JTabbedPane {
 		}
 	}
 
-	public PhotoSettingsConfig(PhotoSettings p) {
+	public PhotoSettingsConfig(PhotoSettings p, OpenRocketDocument document) {
 		super();
 
 		setPreferredSize(new Dimension(240, 320));
@@ -170,25 +172,29 @@ public class PhotoSettingsConfig extends JTabbedPane {
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.pitch")));
 				DoubleModel pitchModel = new DoubleModel(p, "Pitch", UnitGroup.UNITS_ANGLE);
 				add(new EditableSpinner(pitchModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(pitchModel), "pushx, left, wrap");
+				add(new UnitSelector(pitchModel), "growx");
+				add(new BasicSlider(pitchModel.getSliderModel(0, 2 * Math.PI)), "pushx, left, wrap");
 
 				/// Yaw
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.yaw")));
 				DoubleModel yawModel = new DoubleModel(p, "Yaw", UnitGroup.UNITS_ANGLE);
 				add(new EditableSpinner(yawModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(yawModel), "wrap");
+				add(new UnitSelector(yawModel), "growx");
+				add(new BasicSlider(yawModel.getSliderModel(0, 2 * Math.PI)), "wrap");
 
 				/// Roll
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.roll")));
 				DoubleModel rollModel = new DoubleModel(p, "Roll", UnitGroup.UNITS_ANGLE);
 				add(new EditableSpinner(rollModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(rollModel), "wrap");
+				add(new UnitSelector(rollModel), "growx");
+				add(new BasicSlider(rollModel.getSliderModel(0, 2 * Math.PI)), "wrap");
 
 				/// Advance
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.advance")));
 				DoubleModel advanceModel = new DoubleModel(p, "Advance", UnitGroup.UNITS_LENGTH);
 				add(new EditableSpinner(advanceModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(advanceModel), "wrap");
+				add(new UnitSelector(advanceModel), "growx");
+				add(new BasicSlider(advanceModel.getSliderModel(-document.getRocket().getLength(), document.getRocket().getLength())), "wrap");
 
 				// Camera
 				add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.camera"), Style.BOLD), "split, gapright para, span");
@@ -198,25 +204,29 @@ public class PhotoSettingsConfig extends JTabbedPane {
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.vAz")));
 				DoubleModel viewAzModel = new DoubleModel(p, "ViewAz", UnitGroup.UNITS_ANGLE);
 				add(new EditableSpinner(viewAzModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(viewAzModel), "wrap");
+				add(new UnitSelector(viewAzModel), "growx");
+				add(new BasicSlider(viewAzModel.getSliderModel(0, 2 * Math.PI)), "wrap");
 
 				/// View altitude
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.vAlt")));
-				DoubleModel viewAltModle = new DoubleModel(p, "ViewAlt", UnitGroup.UNITS_ANGLE);
+				DoubleModel viewAltModle = new DoubleModel(p, "ViewAlt", UnitGroup.UNITS_ANGLE, -Math.PI / 2, Math.PI / 2);
 				add(new EditableSpinner(viewAltModle.getSpinnerModel()), "growx");
-				add(new UnitSelector(viewAltModle), "wrap");
+				add(new UnitSelector(viewAltModle), "growx");
+				add(new BasicSlider(viewAltModle.getSliderModel(-Math.PI / 2, Math.PI / 2)), "wrap");
 
 				/// View distance
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.vDist")));
 				DoubleModel viewDistanceModel = new DoubleModel(p, "ViewDistance", UnitGroup.UNITS_LENGTH);
 				add(new EditableSpinner(viewDistanceModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(viewDistanceModel), "wrap");
+				add(new UnitSelector(viewDistanceModel), "growx");
+				add(new BasicSlider(viewDistanceModel.getSliderModel(0, 2 * document.getRocket().getLength())), "wrap");
 
 				/// FoV
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.fov")));
-				DoubleModel fovModel = new DoubleModel(p, "Fov", UnitGroup.UNITS_ANGLE);
+				DoubleModel fovModel = new DoubleModel(p, "Fov", UnitGroup.UNITS_ANGLE, Math.PI * 57.3/180, Math.PI * 160/180);
 				add(new EditableSpinner(fovModel.getSpinnerModel()), "growx");
-				add(new UnitSelector(fovModel), "wrap");
+				add(new UnitSelector(fovModel), "growx");
+				add(new BasicSlider(fovModel.getSliderModel(Math.PI * 57.3/180, Math.PI * 160/180)), "wrap");
 			}
 		});
 
@@ -232,19 +242,24 @@ public class PhotoSettingsConfig extends JTabbedPane {
 
 				/// Ambiance
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.amb")));
-				DoubleModel ambianceModel = new DoubleModel(p, "Ambiance", 100, UnitGroup.UNITS_NONE, 0, 100);
-				add(new EditableSpinner(ambianceModel.getSpinnerModel()), "wrap");
+				DoubleModel ambianceModel = new DoubleModel(p, "Ambiance", UnitGroup.UNITS_RELATIVE, 0, 1);
+				add(new EditableSpinner(ambianceModel.getSpinnerModel()), "growx, split 2");
+				add(new UnitSelector(ambianceModel));
+				add(new BasicSlider(ambianceModel.getSliderModel(0, 1)), "pushx, left, wrap");
 
 				/// Light azimuth
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.lightAz")));
 				DoubleModel lightAzModel = new DoubleModel(p, "LightAz", UnitGroup.UNITS_ANGLE);
-				add(new EditableSpinner(lightAzModel.getSpinnerModel()), "split 2");
-				add(new UnitSelector(lightAzModel), "pushx, left, wrap");
+				add(new EditableSpinner(lightAzModel.getSpinnerModel()), "growx, split 2");
+				add(new UnitSelector(lightAzModel));
+				add(new BasicSlider(lightAzModel.getSliderModel(-Math.PI, Math.PI)), "wrap");
 
 				/// Light altitude
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.lightAlt")));
-				DoubleModel lightAltModle = new DoubleModel(p, "LightAlt", UnitGroup.UNITS_ANGLE);
-				add(new EditableSpinner(lightAltModle.getSpinnerModel()), "wrap");
+				DoubleModel lightAltModle = new DoubleModel(p, "LightAlt", UnitGroup.UNITS_ANGLE, -Math.PI / 2, Math.PI / 2);
+				add(new EditableSpinner(lightAltModle.getSpinnerModel()), "growx, split 2");
+				add(new UnitSelector(lightAltModle));
+				add(new BasicSlider(lightAltModle.getSliderModel(-Math.PI / 2, Math.PI / 2)), "wrap");
 
 				// Sky
 				add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.sky"), Style.BOLD), "split, span, gapright para");
@@ -292,7 +307,7 @@ public class PhotoSettingsConfig extends JTabbedPane {
 							setSelectedItem(noSky);
 						}
 					}
-				}, "wrap");
+				}, "spanx, wrap");
 
 				/// Image credit
 				final JLabel creditLabel = new JLabel(trans.get("PhotoSettingsConfig.lbl.skyCredit"));
@@ -304,7 +319,7 @@ public class PhotoSettingsConfig extends JTabbedPane {
 				credit.setOpaque(false);
 				credit.setFocusable(false);
 				credit.setFont(creditLabel.getFont());
-				add(credit);
+				add(credit, "spanx");
 
 				final StateChangeListener skyChange = new StateChangeListener() {
 					@Override
@@ -332,22 +347,28 @@ public class PhotoSettingsConfig extends JTabbedPane {
 				/// Smoke
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.smoke")));
 				BooleanModel smokeModel = new BooleanModel(p, "Smoke");
-				add(new JCheckBox(smokeModel), "split 2, w 15");
+				add(new JCheckBox(smokeModel), "split 2, spanx");
 
-				add(smokeColorButton, "pushx, left, wrap");
+				add(smokeColorButton, "wrap");
 				smokeModel.addEnableComponent(smokeColorButton);
 
 				/// Smoke opacity
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.smokeOpacity")));
-				DoubleModel smokeOpacityModel = new DoubleModel(p, "SmokeOpacity", 100, UnitGroup.UNITS_NONE, 0, 100);
+				DoubleModel smokeOpacityModel = new DoubleModel(p, "SmokeOpacity", UnitGroup.UNITS_RELATIVE, 0, 1);
 				EditableSpinner opacitySpinner = new EditableSpinner(smokeOpacityModel.getSpinnerModel());
-				add(opacitySpinner, "wrap");
+				UnitSelector opacitySelector = new UnitSelector(smokeOpacityModel);
+				BasicSlider opacitySlider = new BasicSlider(smokeOpacityModel.getSliderModel(0, 1));
+				add(opacitySpinner, "growx");
+				add(opacitySelector);
+				add(opacitySlider, "wrap");
 				smokeModel.addEnableComponent(opacitySpinner);
+				smokeModel.addEnableComponent(opacitySelector);
+				smokeModel.addEnableComponent(opacitySlider);
 
 				/// Flame
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.flame")));
 				BooleanModel fireModel = new BooleanModel(p, "Flame");
-				add(new JCheckBox(fireModel), "split 2, w 15");
+				add(new JCheckBox(fireModel), "split 2, spanx");
 
 				add(flameColorButton, "wrap");
 				fireModel.addEnableComponent(flameColorButton);
@@ -357,8 +378,11 @@ public class PhotoSettingsConfig extends JTabbedPane {
 				DoubleModel flameAspectModel = new DoubleModel(p, "FlameAspectRatio", 100, UnitGroup.UNITS_NONE, 25,
 						250);
 				EditableSpinner flameAspectSpinner = new EditableSpinner(flameAspectModel.getSpinnerModel());
-				add(flameAspectSpinner, "wrap");
+				BasicSlider flameAspectSlider = new BasicSlider(flameAspectModel.getSliderModel(25, 250));
+				add(flameAspectSpinner, "growx");
+				add(flameAspectSlider, "skip 1, wrap");
 				fireModel.addEnableComponent(flameAspectSpinner);
+				fireModel.addEnableComponent(flameAspectSlider);
 
 				/// Sparks
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.sparks")));
@@ -369,23 +393,36 @@ public class PhotoSettingsConfig extends JTabbedPane {
 
 				/// Sparks concentration
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.sparkConcentration")));
-				DoubleModel sparkConcentrationModel = new DoubleModel(p, "SparkConcentration", 100,
-						UnitGroup.UNITS_NONE, 0, 100);
+				DoubleModel sparkConcentrationModel = new DoubleModel(p, "SparkConcentration",
+						UnitGroup.UNITS_RELATIVE, 0, 1);
 				EditableSpinner sparkConcentrationSpinner = new EditableSpinner(sparkConcentrationModel.getSpinnerModel());
-				add(sparkConcentrationSpinner, "wrap");
+				UnitSelector sparkConcentrationSelector = new UnitSelector(sparkConcentrationModel);
+				BasicSlider sparkConcentrationSlider = new BasicSlider(sparkConcentrationModel.getSliderModel(0, 1));
+				add(sparkConcentrationSpinner, "growx");
+				add(sparkConcentrationSelector);
+				add(sparkConcentrationSlider, "wrap");
 				sparksModel.addEnableComponent(sparkConcentrationSpinner);
+				sparksModel.addEnableComponent(sparkConcentrationSelector);
+				sparksModel.addEnableComponent(sparkConcentrationSlider);
 
 				/// Spark weight
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.sparkWeight")));
-				DoubleModel sparkWeightModel = new DoubleModel(p, "SparkWeight", 100, UnitGroup.UNITS_NONE, 0, 100);
+				DoubleModel sparkWeightModel = new DoubleModel(p, "SparkWeight", UnitGroup.UNITS_RELATIVE, 0, 1);
 				EditableSpinner sparkWeightSpinner = new EditableSpinner(sparkWeightModel.getSpinnerModel());
-				add(sparkWeightSpinner, "wrap");
+				UnitSelector sparkWeightSelector = new UnitSelector(sparkWeightModel);
+				BasicSlider sparkWeightSlider = new BasicSlider(sparkWeightModel.getSliderModel(0, 1));
+				add(sparkWeightSpinner, "growx");
+				add(sparkWeightSelector);
+				add(sparkWeightSlider, "wrap");
 				sparksModel.addEnableComponent(sparkWeightSpinner);
+				sparksModel.addEnableComponent(sparkWeightSelector);
+				sparksModel.addEnableComponent(sparkWeightSlider);
 
 				/// Exhaust scale
 				add(new JLabel(trans.get("PhotoSettingsConfig.lbl.exhaustScale")));
 				DoubleModel exhaustScaleModel = new DoubleModel(p, "ExhaustScale", 100, UnitGroup.UNITS_NONE, 0, 1000);
-				add(new EditableSpinner(exhaustScaleModel.getSpinnerModel()), "wrap");
+				add(new EditableSpinner(exhaustScaleModel.getSpinnerModel()), "growx");
+				add(new BasicSlider(exhaustScaleModel.getSliderModel(0, 1000)), "skip 1, wrap");
 
 				// Effects
 				add(new StyledLabel(trans.get("PhotoSettingsConfig.lbl.effects"), Style.BOLD), "split, span, gapright para");
diff --git a/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java b/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java
index 28bce901e..d3876b181 100644
--- a/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java
+++ b/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java
@@ -41,7 +41,7 @@ public class RocketInfo implements FigureElement {
 	private final Caret cpCaret = new CPCaret(0,0);
 	private final Caret cgCaret = new CGCaret(0,0);
 	
-	private final UnitGroup stabilityUnits;
+	private UnitGroup stabilityUnits;
 	
 	private FlightConfiguration configuration;
 	private double cg = 0, cp = 0;
@@ -459,5 +459,6 @@ public class RocketInfo implements FigureElement {
 	
 	public void setCurrentConfig(FlightConfiguration newConfig) {
 		this.configuration = newConfig;
+		this.stabilityUnits = UnitGroup.stabilityUnits(newConfig);
 	}
 }
diff --git a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
index f83ef3fb4..6f76a838d 100644
--- a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
+++ b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
@@ -19,6 +19,7 @@ import java.net.URL;
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -116,7 +117,8 @@ public class BasicFrame extends JFrame {
 	 * List of currently open frames.  When the list goes empty
 	 * it is time to exit the application.
 	 */
-	private static final ArrayList<BasicFrame> frames = new ArrayList<BasicFrame>();
+	private static final List<BasicFrame> frames = new ArrayList<BasicFrame>();
+	private static BasicFrame startupFrame = null;	// the frame that was created at startup
 
 
 	/**
@@ -300,23 +302,28 @@ public class BasicFrame extends JFrame {
 		componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() {
 			@Override
 			public void valueChanged(TreeSelectionEvent e) {
-				TreePath selPath = e.getNewLeadSelectionPath();
-				if (selPath == null) return;
-				RocketComponent c = (RocketComponent) selPath.getLastPathComponent();
+				if (tree == null || tree.getSelectionPaths() == null || tree.getSelectionPaths().length == 0
+						|| rocketpanel == null) return;
 
-				if (c instanceof AxialStage || c instanceof Rocket || c instanceof PodSet) {
-					if (rocketpanel == null) return;
-
-					List<RocketComponent> children = new LinkedList<>();
-					for (RocketComponent child : c) {
-						children.add(child);
+				// Get all the components that need to be selected = currently selected components + children of stages/boosters/podsets
+				List<RocketComponent> children = new ArrayList<>(Arrays.asList(rocketpanel.getFigure().getSelection()));
+				for (TreePath p : tree.getSelectionPaths()) {
+					if (p != null) {
+						RocketComponent c = (RocketComponent) p.getLastPathComponent();
+						if (c instanceof AxialStage || c instanceof Rocket || c instanceof PodSet) {
+							Iterator<RocketComponent> iter = c.iterator(false);
+							while (iter.hasNext()) {
+								RocketComponent child = iter.next();
+								children.add(child);
+							}
+						}
 					}
+				}
 
-					// Select all the child components
-					if (rocketpanel.getFigure() != null && rocketpanel.getFigure3d() != null) {
-						rocketpanel.getFigure().setSelection(children.toArray(new RocketComponent[0]));
-						rocketpanel.getFigure3d().setSelection(children.toArray(new RocketComponent[0]));
-					}
+				// Select all the child components
+				if (rocketpanel.getFigure() != null && rocketpanel.getFigure3d() != null) {
+					rocketpanel.getFigure().setSelection(children.toArray(new RocketComponent[0]));
+					rocketpanel.getFigure3d().setSelection(children.toArray(new RocketComponent[0]));
 				}
 			}
 		});
@@ -483,6 +490,10 @@ public class BasicFrame extends JFrame {
 		return result;
 	}
 
+	public RocketPanel getRocketPanel() {
+		return rocketpanel;
+	}
+
 	/**
 	 * Creates the menu for the window.
 	 */
@@ -1225,6 +1236,19 @@ public class BasicFrame extends JFrame {
 		return menu;
 	}
 
+	/**
+	 * Return the frame that was created at the application's startup.
+	 */
+	public static BasicFrame getStartupFrame() {
+		return startupFrame;
+	}
+
+	/**
+	 * Set the frame that is created at the application's startup.
+	 */
+	public static void setStartupFrame(BasicFrame startupFrame) {
+		BasicFrame.startupFrame = startupFrame;
+	}
 
 	/**
 	 * Select the tab on the main pane.
@@ -1267,7 +1291,7 @@ public class BasicFrame extends JFrame {
 
 		for (File file : files) {
 			log.info("Opening file: " + file);
-			if (open(file, parent)) {
+			if (open(file, parent) != null) {
 				MRUDesignFile opts = MRUDesignFile.getInstance();
 				opts.addFile(file.getAbsolutePath());
 			}
@@ -1297,7 +1321,7 @@ public class BasicFrame extends JFrame {
 
 		for (File file : files) {
 			log.info("Opening file: " + file);
-			if (open(file, this)) {
+			if (open(file, this) != null) {
 				MRUDesignFile opts = MRUDesignFile.getInstance();
 				opts.addFile(file.getAbsolutePath());
 			}
@@ -1367,9 +1391,9 @@ public class BasicFrame extends JFrame {
 	 *
 	 * @param file		the file to open.
 	 * @param parent	the parent component for which a progress dialog is opened.
-	 * @return			whether the file was successfully loaded and opened.
+	 * @return			the BasicFrame that was created, or null if not created successfully.
 	 */
-	public static boolean open(File file, Window parent) {
+	public static BasicFrame open(File file, Window parent) {
 		OpenFileWorker worker = new OpenFileWorker(file);
 		return open(worker, file.getName(), parent, false);
 	}
@@ -1382,15 +1406,15 @@ public class BasicFrame extends JFrame {
 	 * @param displayName	the file name to display in dialogs.
 	 * @param parent
 	 * @param openRocketConfigDialog if true, will open the configuration dialog of the rocket.  This is useful for examples.
-	 * @return
+	 * @return the BasicFrame that was created, or null if not created successfully.
 	 */
-	private static boolean open(OpenFileWorker worker, String displayName, Window parent, boolean openRocketConfigDialog) {
+	private static BasicFrame open(OpenFileWorker worker, String displayName, Window parent, boolean openRocketConfigDialog) {
 		////	Open the file in a Swing worker thread
 		log.info("Starting OpenFileWorker");
 		if (!SwingWorkerDialog.runWorker(parent, "Opening file", "Reading " + displayName + "...", worker)) {
 			//	//	User cancelled the operation
 			log.info("User cancelled the OpenFileWorker");
-			return false;
+			return null;
 		}
 
 		////	Handle the document
@@ -1409,7 +1433,7 @@ public class BasicFrame extends JFrame {
 				JOptionPane.showMessageDialog(parent,
 						"File not found: " + displayName,
 						"Error opening file", JOptionPane.ERROR_MESSAGE);
-				return false;
+				return null;
 
 			} else if (cause instanceof RocketLoadException) {
 
@@ -1418,7 +1442,7 @@ public class BasicFrame extends JFrame {
 						"Unable to open file '" + displayName + "': "
 								+ cause.getMessage(),
 								"Error opening file", JOptionPane.ERROR_MESSAGE);
-				return false;
+				return null;
 
 			} else {
 
@@ -1462,7 +1486,7 @@ public class BasicFrame extends JFrame {
 			ComponentConfigDialog.showDialog(frame, doc, doc.getRocket());
 		}
 
-		return true;
+		return frame;
 	}
 
 
@@ -1768,24 +1792,27 @@ public class BasicFrame extends JFrame {
 	/**
 	 * Opens a new design file or the last design file, if set in the preferences.
 	 * Can be used for reopening the application or opening it the first time.
+	 * @return the BasicFrame that was created
 	 */
-	public static void reopen() {
+	public static BasicFrame reopen() {
 		if (!Application.getPreferences().isAutoOpenLastDesignOnStartupEnabled()) {
-			BasicFrame.newAction();
+			return BasicFrame.newAction();
 		} else {
 			String lastFile = MRUDesignFile.getInstance().getLastEditedDesignFile();
 			if (lastFile != null) {
 				log.info("Opening last design file: " + lastFile);
-				if (!BasicFrame.open(new File(lastFile), null)) {
+				BasicFrame frame = BasicFrame.open(new File(lastFile), null);
+				if (frame == null) {
 					MRUDesignFile.getInstance().removeFile(lastFile);
-					BasicFrame.newAction();
+					return BasicFrame.newAction();
 				}
 				else {
 					MRUDesignFile.getInstance().addFile(lastFile);
+					return frame;
 				}
 			}
 			else {
-				BasicFrame.newAction();
+				return BasicFrame.newAction();
 			}
 		}
 	}
@@ -1793,8 +1820,9 @@ public class BasicFrame extends JFrame {
 
 	/**
 	 * Open a new design window with a basic rocket+stage.
+	 * @return the BasicFrame that was created
 	 */
-	public static void newAction() {
+	public static BasicFrame newAction() {
 		log.info("New action initiated");
 
 		OpenRocketDocument doc = OpenRocketDocumentFactory.createNewRocket();
@@ -1802,6 +1830,7 @@ public class BasicFrame extends JFrame {
 		BasicFrame frame = new BasicFrame(doc);
 		frame.replaceable = true;
 		frame.setVisible(true);
+		return frame;
 	}
 
 
@@ -1865,6 +1894,13 @@ public class BasicFrame extends JFrame {
 		return null;
 	}
 
+	/**
+	 * Return all BasicFrame instances
+	 */
+	public static List<BasicFrame> getAllFrames() {
+		return frames;
+	}
+
 	/**
 	 * Checks whether all the BasicFrames are closed.
 	 * @return true if all the BasicFrames are closed, false if not
diff --git a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java
index 8ed2338c9..0ff03e261 100644
--- a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java
+++ b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java
@@ -488,7 +488,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
 				}
 			}
 			
-			ComponentConfigDialog.showDialog(parent, document, component, false);
+			ComponentConfigDialog.showDialog(parent, document, component, false, false);
 		}
 	}
 	
diff --git a/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java b/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java
index 5582e4fca..3ff152d82 100644
--- a/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java
+++ b/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java
@@ -73,7 +73,7 @@ public final class MRUDesignFileAction extends JMenu {
             @Override
             public void actionPerformed(ActionEvent e) {
                 String command = e.getActionCommand();
-                if (BasicFrame.open(new File(command), parent)) {
+                if (BasicFrame.open(new File(command), parent) != null) {
                     MRUDesignFile.getInstance().addFile(command);
                 }
                 else {
diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java
index fb174692a..11c991e1f 100644
--- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java
+++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/RecoveryConfigurationPanel.java
@@ -1,9 +1,12 @@
 package net.sf.openrocket.gui.main.flightconfigpanel;
 
 import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.swing.AbstractAction;
@@ -162,6 +165,30 @@ public class RecoveryConfigurationPanel extends FlightConfigurablePanel<Recovery
 		return recoveryTable;
 	}
 
+	@Override
+	protected void installTableListener() {
+		super.installTableListener();
+
+		table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				updateComponentSelection(e);
+			}
+		});
+
+		table.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				updateComponentSelection(new ListSelectionEvent(this, 0, 0, false));
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+
+			}
+		});
+	}
+
 	public void selectDeployment() {
 		List<RecoveryDevice> devices = getSelectedComponents();
 		List<FlightConfigurationId> fcIds = getSelectedConfigurationIds();
@@ -239,6 +266,16 @@ public class RecoveryConfigurationPanel extends FlightConfigurablePanel<Recovery
 		popupMenuFull.show(e.getComponent(), e.getX(), e.getY());
 	}
 
+	public void updateComponentSelection(ListSelectionEvent e) {
+		if (e.getValueIsAdjusting() || getSelectedComponents() == null) {
+			return;
+		}
+		List<RocketComponent> components = new ArrayList<>(getSelectedComponents());
+		if (components.size() == 0) return;
+
+		flightConfigurationPanel.setSelectedComponents(components);
+	}
+
 	public void updateButtonState() {
 		boolean componentSelected = getSelectedComponent() != null;
 		selectDeploymentButton.setEnabled(componentSelected);
diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java
index 6ae182dcd..ccf27e1d1 100644
--- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java
+++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java
@@ -1,9 +1,12 @@
 package net.sf.openrocket.gui.main.flightconfigpanel;
 
 import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.swing.AbstractAction;
@@ -27,6 +30,7 @@ import net.sf.openrocket.rocketcomponent.AxialStage;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
 import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
 import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration.SeparationEvent;
 import net.sf.openrocket.startup.Application;
@@ -170,6 +174,30 @@ public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialS
 		return separationTable;
 	}
 
+	@Override
+	protected void installTableListener() {
+		super.installTableListener();
+
+		table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				updateComponentSelection(e);
+			}
+		});
+
+		table.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				updateComponentSelection(new ListSelectionEvent(this, 0, 0, false));
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+
+			}
+		});
+	}
+
 	public void selectSeparation() {
 		List<AxialStage> stages = getSelectedComponents();
 		List<FlightConfigurationId> fcIds = getSelectedConfigurationIds();
@@ -248,6 +276,16 @@ public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialS
 		popupMenuFull.show(e.getComponent(), e.getX(), e.getY());
 	}
 
+	public void updateComponentSelection(ListSelectionEvent e) {
+		if (e.getValueIsAdjusting() || getSelectedComponents() == null) {
+			return;
+		}
+		List<RocketComponent> components = new ArrayList<>(getSelectedComponents());
+		if (components.size() == 0) return;
+
+		flightConfigurationPanel.setSelectedComponents(components);
+	}
+
 	public void updateButtonState() {
 		boolean componentSelected = getSelectedComponent() != null;
 		selectSeparationButton.setEnabled(componentSelected);
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/EmptyShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/EmptyShapes.java
new file mode 100644
index 000000000..35b048551
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/EmptyShapes.java
@@ -0,0 +1,122 @@
+package net.sf.openrocket.gui.rocketfigure;
+
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.Transformation;
+
+import java.awt.Shape;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Shapes of an "empty"/virtual object, e.g. a podset without any children.
+ * The shape is a center square with additional lines on the north, east, south and west side of the square.
+ *
+ * @author Sibo Van Gool <sibo.vangool@hotmail.com>
+ */
+public class EmptyShapes extends RocketComponentShape {
+    /**
+     * Returns the empty shape in the side view.
+     * @param radius radius of the center square
+     */
+    public static Shape[] getShapesSide(final Transformation transformation, final double radius) {
+        final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
+        double x = instanceAbsoluteLocation.x;
+        double y = instanceAbsoluteLocation.y;
+
+        double lineLength = getLineLength(radius);     // Length of the line protruding the center square
+
+        final Shape[] s = new Shape[5];
+        // Center square
+        s[0] = new Rectangle2D.Double(x - radius, y - radius, 2 * radius, 2 * radius);
+        // Line North
+        s[1] = new Line2D.Double(x, y + radius, x, y + radius + lineLength);
+        // Line East
+        s[2] = new Line2D.Double(x + radius, y, x + radius + lineLength, y);
+        // Line South
+        s[3] = new Line2D.Double(x, y - radius, x, y - radius - lineLength);
+        // Line West
+        s[4] = new Line2D.Double(x - radius, y, x - radius - lineLength, y);
+
+        return s;
+    }
+
+    /**
+     * Returns the empty shape in the side view, with an additional square encompassing the shape that can be used
+     * for selecting the object.
+     * @param radius radius of the center square
+     */
+    public static Shape[] getShapesSideWithSelectionSquare(final Transformation transformation, final double radius) {
+        final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
+        double x = instanceAbsoluteLocation.x;
+        double y = instanceAbsoluteLocation.y;
+
+        double lineLength = getLineLength(radius);     // Length of the line protruding the center square
+
+        Shape[] shapes = getShapesSide(transformation, radius);
+
+        // Invisible shape for selecting the component (= a square encompassing the component)
+        Shape selectionShape = new Rectangle2D.Double(x - radius - lineLength, y - radius - lineLength,
+                lineLength * 2 + radius * 2, lineLength * 2 + radius * 2);
+
+        Shape[] finalShapes = new Shape[shapes.length + 1];
+        System.arraycopy(shapes, 0, finalShapes, 0, shapes.length);
+        finalShapes[finalShapes.length - 1] = selectionShape;
+
+        return finalShapes;
+    }
+
+    /**
+     * Returns the empty shape in the side view.
+     * @param radius radius of the center square
+     */
+    public static Shape[] getShapesBack(final Transformation transformation, final double radius) {
+        final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
+        double z = instanceAbsoluteLocation.z;
+        double y = instanceAbsoluteLocation.y;
+
+        double lineLength = getLineLength(radius);     // Length of the line protruding the center square
+
+        final Shape[] s = new Shape[5];
+        // Center square
+        s[0] = new Rectangle2D.Double(z - radius, y - radius, 2 * radius, 2 * radius);
+        // Line North
+        s[1] = new Line2D.Double(z, y + radius, z, y + radius + lineLength);
+        // Line East
+        s[2] = new Line2D.Double(z + radius, y, z + radius + lineLength, y);
+        // Line South
+        s[3] = new Line2D.Double(z, y - radius, z, y - radius - lineLength);
+        // Line West
+        s[4] = new Line2D.Double(z - radius, y, z - radius - lineLength, y);
+
+        return s;
+    }
+
+    /**
+     * Returns the empty shape in the back view, with an additional square encompassing the shape that can be used
+     * for selecting the object.
+     * @param radius radius of the center square
+     */
+    public static Shape[] getShapesBackWithSelectionSquare(final Transformation transformation, final double radius) {
+        final Coordinate instanceAbsoluteLocation = transformation.transform(Coordinate.ZERO);
+        double z = instanceAbsoluteLocation.z;
+        double y = instanceAbsoluteLocation.y;
+
+        double lineLength = getLineLength(radius);     // Length of the line protruding the center square
+
+        Shape[] shapes = getShapesBack(transformation, radius);
+
+        // Invisible shape for selecting the component (= a square encompassing the component)
+        Shape selectionShape = new Rectangle2D.Double(z - radius - lineLength, y - radius - lineLength,
+                lineLength * 2 + radius * 2, lineLength * 2 + radius * 2);
+
+        Shape[] finalShapes = new Shape[shapes.length + 1];
+        System.arraycopy(shapes, 0, finalShapes, 0, shapes.length);
+        finalShapes[finalShapes.length - 1] = selectionShape;
+
+        return finalShapes;
+    }
+
+    private static double getLineLength(double radius) {
+        return radius * 3;
+    }
+}
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/ParallelStageShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/ParallelStageShapes.java
new file mode 100644
index 000000000..565a23591
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/ParallelStageShapes.java
@@ -0,0 +1,48 @@
+package net.sf.openrocket.gui.rocketfigure;
+
+import net.sf.openrocket.rocketcomponent.ParallelStage;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.Color;
+import net.sf.openrocket.util.Transformation;
+
+import java.awt.Shape;
+
+public class ParallelStageShapes extends RocketComponentShape {
+    public static final Color boosterColor = new Color(198,163,184);
+
+    public static RocketComponentShape[] getShapesSide(final RocketComponent component, final Transformation transformation) {
+        ParallelStage booster = (ParallelStage)component;
+        double radius = getDisplayRadius(booster);
+
+        Shape[] s = EmptyShapes.getShapesSideWithSelectionSquare(transformation, radius);
+        RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
+
+        // Set the color of the shapes
+        for (int i = 0; i < shapes.length - 1; i++) {
+            shapes[i].setColor(boosterColor);
+        }
+        shapes[shapes.length - 1].setColor(Color.INVISIBLE);
+
+        return shapes;
+    }
+
+    public static RocketComponentShape[] getShapesBack(final RocketComponent component, final Transformation transformation) {
+        ParallelStage booster = (ParallelStage)component;
+        double radius = getDisplayRadius(booster);
+
+        Shape[] s = EmptyShapes.getShapesBackWithSelectionSquare(transformation, radius);
+        RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
+
+        // Set the color of the shapes
+        for (int i = 0; i < shapes.length - 1; i++) {
+            shapes[i].setColor(boosterColor);
+        }
+        shapes[shapes.length - 1].setColor(Color.INVISIBLE);
+
+        return shapes;
+    }
+
+    private static double getDisplayRadius(ParallelStage booster) {
+        return booster.getRocket().getBoundingRadius() * 0.03;
+    }
+}
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/PodSetShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/PodSetShapes.java
new file mode 100644
index 000000000..7ef928f2d
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/PodSetShapes.java
@@ -0,0 +1,48 @@
+package net.sf.openrocket.gui.rocketfigure;
+
+import net.sf.openrocket.rocketcomponent.PodSet;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.Color;
+import net.sf.openrocket.util.Transformation;
+
+import java.awt.Shape;
+
+public class PodSetShapes extends RocketComponentShape {
+    public static final Color podsetColor = new Color(160,160,215);
+
+    public static RocketComponentShape[] getShapesSide(final RocketComponent component, final Transformation transformation) {
+        PodSet podset = (PodSet)component;
+        double radius = getDisplayRadius(podset);
+
+        Shape[] s = EmptyShapes.getShapesSideWithSelectionSquare(transformation, radius);
+        RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
+
+        // Set the color of the shapes
+        for (int i = 0; i < shapes.length - 1; i++) {
+            shapes[i].setColor(podsetColor);
+        }
+        shapes[shapes.length - 1].setColor(Color.INVISIBLE);
+
+        return shapes;
+    }
+
+    public static RocketComponentShape[] getShapesBack(final RocketComponent component, final Transformation transformation) {
+        PodSet podset = (PodSet)component;
+        double radius = getDisplayRadius(podset);
+
+        Shape[] s = EmptyShapes.getShapesBackWithSelectionSquare(transformation, radius);
+        RocketComponentShape[] shapes = RocketComponentShape.toArray(s, component);
+
+        // Set the color of the shapes
+        for (int i = 0; i < shapes.length - 1; i++) {
+            shapes[i].setColor(podsetColor);
+        }
+        shapes[shapes.length - 1].setColor(Color.INVISIBLE);
+
+        return shapes;
+    }
+
+    private static double getDisplayRadius(PodSet podset) {
+        return podset.getRocket().getBoundingRadius() * 0.03;
+    }
+}
diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java b/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java
index 725713b80..c132bfd3d 100644
--- a/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java
+++ b/swing/src/net/sf/openrocket/gui/rocketfigure/RocketComponentShape.java
@@ -64,6 +64,10 @@ public class RocketComponentShape {
 		return new RocketComponentShape[0];
 	}
 
+	public Color getColor() {
+		return color;
+	}
+
 	public void setColor(Color color) {
 		this.color = color;
 	}
diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
index 3226abee2..6e4bf9e4b 100644
--- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
+++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
@@ -17,6 +17,9 @@ import java.awt.geom.Rectangle2D;
 import java.util.*;
 import java.util.Map.Entry;
 
+import net.sf.openrocket.rocketcomponent.AxialStage;
+import net.sf.openrocket.rocketcomponent.ParallelStage;
+import net.sf.openrocket.rocketcomponent.PodSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -26,7 +29,6 @@ import net.sf.openrocket.gui.util.ColorConversion;
 import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.MotorConfiguration;
-import net.sf.openrocket.rocketcomponent.ComponentAssembly;
 import net.sf.openrocket.rocketcomponent.FlightConfiguration;
 import net.sf.openrocket.rocketcomponent.InstanceContext;
 import net.sf.openrocket.rocketcomponent.MotorMount;
@@ -52,6 +54,7 @@ import net.sf.openrocket.util.Transformation;
 public class RocketFigure extends AbstractScaleFigure {
 
     private final static Logger log = LoggerFactory.getLogger(FinPointFigure.class);
+	protected final SwingPreferences preferences = (SwingPreferences) Application.getPreferences();
 	
 	private static final String ROCKET_FIGURE_PACKAGE = "net.sf.openrocket.gui.rocketfigure";
 	private static final String ROCKET_FIGURE_SUFFIX = "Shapes";
@@ -378,6 +381,20 @@ public class RocketFigure extends AbstractScaleFigure {
 		
 		for(Entry<RocketComponent, ArrayList<InstanceContext>> entry: config.getActiveInstances().entrySet() ) {
 			final RocketComponent comp = entry.getKey();
+
+			// Only draw podsets when they are selected
+			if ((comp instanceof PodSet || comp instanceof ParallelStage) && preferences.isShowMarkers()) {
+				boolean selected = false;
+
+				// Check if component is in the selection
+				for (RocketComponent component : selection) {
+					if (comp == component) {
+						selected = true;
+						break;
+					}
+				}
+				if (!selected) continue;
+			}
 			
 			final ArrayList<InstanceContext> contextList = entry.getValue();
 
@@ -390,8 +407,12 @@ public class RocketFigure extends AbstractScaleFigure {
 	
 	/**
 	 * Gets the shapes required to draw the component.
-	 * 
-	 * @param component
+	 *
+	 * @param allShapes output buffer for the shapes to add to
+	 * @param viewType the view type to draw the component in
+	 * @param component component to draw and add to <allShapes>
+	 * @param transformation transformation to apply to the component before drawing it
+	 * @param color color to draw the component in
 	 *
 	 * @return the <code>ArrayList</code> containing all the shapes to draw.
 	 */
@@ -399,10 +420,11 @@ public class RocketFigure extends AbstractScaleFigure {
 			PriorityQueue<RocketComponentShape> allShapes,  // this is the output parameter
 			final RocketPanel.VIEW_TYPE viewType, 
 			final RocketComponent component, 
-			final Transformation transformation) {
+			final Transformation transformation,
+			final net.sf.openrocket.util.Color color) {
 		Reflection.Method m;
 		
-		if(( component instanceof Rocket)||( component instanceof ComponentAssembly )){
+		if ((component instanceof Rocket) || (component instanceof AxialStage && !(component instanceof ParallelStage))){
 			// no-op; no shapes here
 			return allShapes;
 		}
@@ -431,9 +453,35 @@ public class RocketFigure extends AbstractScaleFigure {
 		
 	
 		RocketComponentShape[] returnValue =  (RocketComponentShape[]) m.invokeStatic(component, transformation);
+
+		if (color != null) {
+			for (RocketComponentShape rcs : returnValue) {
+				if (rcs.getColor() == net.sf.openrocket.util.Color.INVISIBLE) continue;	// don't change the color of invisible (often selection) components
+				rcs.setColor(color);
+			}
+		}
+
 		allShapes.addAll(Arrays.asList(returnValue));
 		return allShapes;
 	}
+
+	/**
+	 * Gets the shapes required to draw the component.
+	 *
+	 * @param allShapes output buffer for the shapes to add to
+	 * @param viewType the view type to draw the component in
+	 * @param component component to draw and add to <allShapes>
+	 * @param transformation transformation to apply to the component before drawing it
+	 *
+	 * @return the <code>ArrayList</code> containing all the shapes to draw.
+	 */
+	private static PriorityQueue<RocketComponentShape> addThisShape(
+			PriorityQueue<RocketComponentShape> allShapes,  // this is the output parameter
+			final RocketPanel.VIEW_TYPE viewType,
+			final RocketComponent component,
+			final Transformation transformation) {
+		return addThisShape(allShapes, viewType, component, transformation, null);
+	}
 	
 
 	/**
diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
index 92df95906..9f4f309f7 100644
--- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
+++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
@@ -252,7 +252,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
 		});
 	}
 
-	private void updateFigures() {
+	public void updateFigures() {
 		if (!is3d)
 			figure.updateFigure();
 		else
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
index 2bfe10afc..03b9ab944 100644
--- a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
+++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
@@ -151,7 +151,7 @@ public class SimulationEditDialog extends JDialog {
 			
 			final Rocket rkt = document.getRocket();
 			final FlightConfiguration config = rkt.getFlightConfiguration(simulationList[0].getFlightConfigurationId());
-			final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt);
+			final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt, false);
 			configComboBox.setSelectedItem(config);
 			
 			//// Select the motor configuration to use.
diff --git a/swing/src/net/sf/openrocket/gui/util/WindowLocationUtil.java b/swing/src/net/sf/openrocket/gui/util/WindowLocationUtil.java
new file mode 100644
index 000000000..d4443954c
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/util/WindowLocationUtil.java
@@ -0,0 +1,74 @@
+package net.sf.openrocket.gui.util;
+
+import java.awt.GraphicsDevice;
+import java.awt.Window;
+
+/**
+ * Helper class for setting the location of a Swing window. E.g. to check when the window is outside the screen and
+ * recenter it if so.
+ *
+ * @author Sibo Van Gool <sibo.vangool@hotmail.com>
+ */
+public abstract class WindowLocationUtil {
+    /**
+     * Sets the location of the window, but don't go outside the screen.
+     * @param window the window to move
+     * @param x the target x position on the screen
+     * @param y the target y position on the screen
+     */
+    public static void setLocationWithinScreen(Window window, int x, int y) {
+        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
+        java.awt.Dimension windowSize = window.getSize();
+        int screenWidth = screenSize.width;
+        int screenHeight = screenSize.height;
+        int windowWidth = windowSize.width;
+        int windowHeight = windowSize.height;
+        int xPos = x;
+        int yPos = y;
+        if (xPos + windowWidth > screenWidth) {
+            xPos = screenWidth - windowWidth;
+        }
+        if (yPos + windowHeight > screenHeight) {
+            yPos = screenHeight - windowHeight;
+        }
+        window.setLocation(xPos, yPos);
+    }
+
+    /**
+     * Moves the window to the center of the screen if its location is outside the boundary of the screen.
+     * @param window window to move
+     */
+    public static void moveIfOutsideOfMonitor(Window window) {
+        GraphicsDevice currentDevice = window.getGraphicsConfiguration().getDevice();
+        if (currentDevice != null && window.isVisible() &&
+                !currentDevice.getDefaultConfiguration().getBounds().contains(window.getLocationOnScreen())) {
+            int width = currentDevice.getDefaultConfiguration().getBounds().width;
+            int height = currentDevice.getDefaultConfiguration().getBounds().height;
+            window.setLocation(
+                    ((width / 2) - (window.getSize().width / 2)) + currentDevice.getDefaultConfiguration().getBounds().x,
+                    ((height / 2) - (window.getSize().height / 2)) + currentDevice.getDefaultConfiguration().getBounds().y
+            );
+        }
+    }
+
+    /**
+     * Moves the window to the center of the screen if it is on another monitor as the parent window, or if its location
+     * is outside the boundary of the parent's monitor screen.
+     * @param window window to move
+     * @param parent parent window
+     */
+    public static void moveIfOutsideOfParentMonitor(Window window, Window parent) {
+        GraphicsDevice parentDevice = parent.getGraphicsConfiguration().getDevice();
+        GraphicsDevice currentDevice = window.getGraphicsConfiguration().getDevice();
+        if (parentDevice != null && (currentDevice == null || currentDevice != parentDevice ||
+                (window.isVisible() && !parentDevice.getDefaultConfiguration().getBounds().contains(
+                        window.getLocationOnScreen())))) {
+            int width = parentDevice.getDefaultConfiguration().getBounds().width;
+            int height = parentDevice.getDefaultConfiguration().getBounds().height;
+            window.setLocation(
+                    ((width / 2) - (window.getSize().width / 2)) + parentDevice.getDefaultConfiguration().getBounds().x,
+                    ((height / 2) - (window.getSize().height / 2)) + parentDevice.getDefaultConfiguration().getBounds().y
+            );
+        }
+    }
+}
diff --git a/swing/src/net/sf/openrocket/startup/SwingStartup.java b/swing/src/net/sf/openrocket/startup/SwingStartup.java
index 5d6ff3386..462549e11 100644
--- a/swing/src/net/sf/openrocket/startup/SwingStartup.java
+++ b/swing/src/net/sf/openrocket/startup/SwingStartup.java
@@ -223,7 +223,8 @@ public class SwingStartup {
 		// Starting action (load files or open new document)
 		log.info("Opening main application window");
 		if (!handleCommandLine(args)) {
-			BasicFrame.reopen();
+			BasicFrame startupFrame = BasicFrame.reopen();
+			BasicFrame.setStartupFrame(startupFrame);
 		}
 		
 		// Check whether update info has been fetched or whether it needs more time
@@ -298,7 +299,7 @@ public class SwingStartup {
 		// Check command-line for files
 		boolean opened = false;
 		for (String file : args) {
-			if (BasicFrame.open(new File(file), null)) {
+			if (BasicFrame.open(new File(file), null) != null) {
 				opened = true;
 			}
 		}
diff --git a/swing/test/net/sf/openrocket/IntegrationTest.java b/swing/test/net/sf/openrocket/IntegrationTest.java
index 24cb6178e..e0a280f09 100644
--- a/swing/test/net/sf/openrocket/IntegrationTest.java
+++ b/swing/test/net/sf/openrocket/IntegrationTest.java
@@ -71,7 +71,7 @@ public class IntegrationTest {
 	private Action undoAction, redoAction;
 	
 	private AerodynamicCalculator aeroCalc = new BarrowmanCalculator();
-	private FlightConfiguration config;
+	private FlightConfigurationId fcid;
 	private FlightConditions conditions;
 	private String massComponentID = null;
 	
@@ -112,14 +112,12 @@ public class IntegrationTest {
 		
 		undoAction = UndoRedoAction.newUndoAction(document);
 		redoAction = UndoRedoAction.newRedoAction(document);
-        FlightConfigurationId fcid = document.getSimulation(0).getFlightConfigurationId();
-		config = document.getRocket().getFlightConfiguration(fcid);
+        fcid = document.getSimulation(0).getFlightConfigurationId();
+		FlightConfiguration config = document.getRocket().getFlightConfiguration(fcid);
 		conditions = new FlightConditions(config);
 		
 		// Test undo state
 		checkUndoState(null, null);
-		
-		InnerTube mmt = (InnerTube)config.getRocket().getChild(0).getChild(1).getChild(2);
 		 
 		// Compute cg+cp + altitude
 	    //   double cgx, double mass, double cpx, double cna)
@@ -330,6 +328,7 @@ public class IntegrationTest {
 	}
 	
 	private void checkCgCp(double cgx, double mass, double cpx, double cna) {
+		FlightConfiguration config = document.getRocket().getFlightConfiguration(fcid);
 		final RigidBody launchData = MassCalculator.calculateLaunch(config);
 		final Coordinate cg = launchData.getCenterOfMass();
 		assertEquals(cgx, cg.x, 0.001);