Merge branch 'unstable' into issue-1818
This commit is contained in:
commit
29020856cb
@ -470,6 +470,8 @@ SimulationExtension.javacode.name = Java code
|
|||||||
SimulationExtension.javacode.name.none = none
|
SimulationExtension.javacode.name.none = none
|
||||||
SimulationExtension.javacode.desc = Add a custom SimulationListener to the simulation
|
SimulationExtension.javacode.desc = Add a custom SimulationListener to the simulation
|
||||||
SimulationExtension.javacode.className = Fully-qualified Java class name:
|
SimulationExtension.javacode.className = Fully-qualified Java class name:
|
||||||
|
SimulationExtension.javacode.classnotfound = Could not find class
|
||||||
|
SimulationExtension.javacode.couldnotinstantiate = <html>Could not instantiate class %s.<br>Does it have a zero-argument, or @Inject constructor?</html>
|
||||||
|
|
||||||
SimulationExtension.scripting.name = {language} script
|
SimulationExtension.scripting.name = {language} script
|
||||||
SimulationExtension.scripting.desc = Extend OpenRocket simulations by custom scripts.
|
SimulationExtension.scripting.desc = Extend OpenRocket simulations by custom scripts.
|
||||||
@ -552,6 +554,7 @@ SimuRunDlg.msg.errorOccurred = An error occurred during the simulation:
|
|||||||
|
|
||||||
BasicEventSimulationEngine.error.noMotorsDefined = No motors defined in the simulation.
|
BasicEventSimulationEngine.error.noMotorsDefined = No motors defined in the simulation.
|
||||||
BasicEventSimulationEngine.error.earlyMotorBurnout = Motor burnout without liftoff.
|
BasicEventSimulationEngine.error.earlyMotorBurnout = Motor burnout without liftoff.
|
||||||
|
BasicEventSimulationEngine.error.noConfiguredIgnition = No motors configured to ignite at liftoff
|
||||||
BasicEventSimulationEngine.error.noIgnition = No motors ignited.
|
BasicEventSimulationEngine.error.noIgnition = No motors ignited.
|
||||||
BasicEventSimulationEngine.error.NaNResult = Simulation resulted in not-a-number (NaN) value, please report a bug.
|
BasicEventSimulationEngine.error.NaNResult = Simulation resulted in not-a-number (NaN) value, please report a bug.
|
||||||
|
|
||||||
@ -1028,6 +1031,8 @@ FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points
|
|||||||
FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Delete point
|
FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Delete point
|
||||||
FreeformFinSetConfig.lbl.scaleFin = Scale Fin
|
FreeformFinSetConfig.lbl.scaleFin = Scale Fin
|
||||||
FreeformFinSetConfig.lbl.exportCSV = Export CSV
|
FreeformFinSetConfig.lbl.exportCSV = Export CSV
|
||||||
|
FreeformFinSetConfig.lbl.deletePoint = Delete point
|
||||||
|
FreeformFinSetConfig.lbl.insertPoint = Insert point
|
||||||
|
|
||||||
!TubeFinSetConfig
|
!TubeFinSetConfig
|
||||||
TubeFinSetCfg.lbl.Nbroffins = Number of fins:
|
TubeFinSetCfg.lbl.Nbroffins = Number of fins:
|
||||||
@ -1827,7 +1832,7 @@ PlotConfiguration.Groundtrack = Ground track
|
|||||||
! Warning
|
! Warning
|
||||||
Warning.LargeAOA.str1 = Large angle of attack encountered.
|
Warning.LargeAOA.str1 = Large angle of attack encountered.
|
||||||
Warning.LargeAOA.str2 = Large angle of attack encountered (
|
Warning.LargeAOA.str2 = Large angle of attack encountered (
|
||||||
Warning.DISCONTINUITY = Discontinuity in rocket body diameter.
|
Warning.DISCONTINUITY = Discontinuity in rocket body diameter
|
||||||
Warning.THICK_FIN = Thick fins may not be modeled accurately.
|
Warning.THICK_FIN = Thick fins may not be modeled accurately.
|
||||||
Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate.
|
Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate.
|
||||||
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
||||||
@ -1844,6 +1849,7 @@ Warning.ZERO_LENGTH_BODY = Zero length bodies may not result in accurate simulat
|
|||||||
Warning.ZERO_RADIUS_BODY = Zero length bodies may not result in accurate simulations.
|
Warning.ZERO_RADIUS_BODY = Zero length bodies may not result in accurate simulations.
|
||||||
Warning.TUBE_SEPARATION = Space between tube fins may not result in accurate simulations.
|
Warning.TUBE_SEPARATION = Space between tube fins may not result in accurate simulations.
|
||||||
Warning.TUBE_OVERLAP = Overlapping tube fins may not result in accurate simulations.
|
Warning.TUBE_OVERLAP = Overlapping tube fins may not result in accurate simulations.
|
||||||
|
Warning.EMPTY_BRANCH = Simulation branch contains no data
|
||||||
Warning.SEPARATION_ORDER = Stages separated in an unreasonable order
|
Warning.SEPARATION_ORDER = Stages separated in an unreasonable order
|
||||||
|
|
||||||
! Scale dialog
|
! Scale dialog
|
||||||
|
|||||||
@ -1315,7 +1315,7 @@ PlotConfiguration.Simulationtime = Simulacn
|
|||||||
! Warning
|
! Warning
|
||||||
Warning.LargeAOA.str1 = Velký úhel nábehu.
|
Warning.LargeAOA.str1 = Velký úhel nábehu.
|
||||||
Warning.LargeAOA.str2 = Velký úhel nábehu (
|
Warning.LargeAOA.str2 = Velký úhel nábehu (
|
||||||
Warning.DISCONTINUITY = Nespojitost v prumeru tela rakety.
|
Warning.DISCONTINUITY = Nespojitost v prumeru tela rakety
|
||||||
Warning.THICK_FIN = Tlou\u0161tka stabilizátoru se nemu\u017Ee modelovat presne.
|
Warning.THICK_FIN = Tlou\u0161tka stabilizátoru se nemu\u017Ee modelovat presne.
|
||||||
Warning.JAGGED_EDGED_FIN = Zubaté hrany stabilizátoru mohou být vypocteny nepresne.
|
Warning.JAGGED_EDGED_FIN = Zubaté hrany stabilizátoru mohou být vypocteny nepresne.
|
||||||
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
||||||
|
|||||||
@ -1225,7 +1225,7 @@ TrapezoidFinSetCfg.tab.Generalproperties = Propiedades generales
|
|||||||
! TubeCoupler
|
! TubeCoupler
|
||||||
TubeCoupler.TubeCoupler = Acoplador
|
TubeCoupler.TubeCoupler = Acoplador
|
||||||
|
|
||||||
Warning.DISCONTINUITY = Discontinuidad en el di\u00e1metro del fuselaje.
|
Warning.DISCONTINUITY = Discontinuidad en el di\u00e1metro del fuselaje
|
||||||
Warning.FILE_INVALID_PARAMETER = Par\u00e1metro encontrado no v\u00e1lido, ignorado.
|
Warning.FILE_INVALID_PARAMETER = Par\u00e1metro encontrado no v\u00e1lido, ignorado.
|
||||||
Warning.JAGGED_EDGED_FIN = El perfil afilado de las aletas puede ser inexacto.
|
Warning.JAGGED_EDGED_FIN = El perfil afilado de las aletas puede ser inexacto.
|
||||||
Warning.LISTENERS_AFFECTED = Las Extensiones se ejecutaron con la simulaci\u00f3n del vuelo
|
Warning.LISTENERS_AFFECTED = Las Extensiones se ejecutaron con la simulaci\u00f3n del vuelo
|
||||||
|
|||||||
@ -1219,7 +1219,7 @@ TrapezoidFinSetCfg.tab.Generalproperties = Propri\u00E9t\u00E9s g\u00E9n\u00E9ra
|
|||||||
! TubeCoupler
|
! TubeCoupler
|
||||||
TubeCoupler.TubeCoupler = Coupleur de tube
|
TubeCoupler.TubeCoupler = Coupleur de tube
|
||||||
|
|
||||||
Warning.DISCONTINUITY = Discontinuit\u00E9 dans le diam\u00E8tre du corps de la fus\u00E9e.
|
Warning.DISCONTINUITY = Discontinuit\u00E9 dans le diam\u00E8tre du corps de la fus\u00E9e
|
||||||
Warning.FILE_INVALID_PARAMETER = Param\u00E8tre invalide rencontr\u00E9, ignorer.
|
Warning.FILE_INVALID_PARAMETER = Param\u00E8tre invalide rencontr\u00E9, ignorer.
|
||||||
Warning.JAGGED_EDGED_FIN = Des ailerons aux bords irr\u00E9guliers ne seront pas mod\u00E9lis\u00E9s correctement.
|
Warning.JAGGED_EDGED_FIN = Des ailerons aux bords irr\u00E9guliers ne seront pas mod\u00E9lis\u00E9s correctement.
|
||||||
Warning.LISTENERS_AFFECTED = Les \u00E9couteurs ont modifi\u00E9 la simulation de vol
|
Warning.LISTENERS_AFFECTED = Les \u00E9couteurs ont modifi\u00E9 la simulation de vol
|
||||||
|
|||||||
@ -1379,7 +1379,7 @@ PlotConfiguration.Simulationtime = Intervallo temporale della simulazione e temp
|
|||||||
! Warning
|
! Warning
|
||||||
Warning.LargeAOA.str1 = Incontrato grande angolo d'attacco.
|
Warning.LargeAOA.str1 = Incontrato grande angolo d'attacco.
|
||||||
Warning.LargeAOA.str2 = Incontrato grande angolo d'attacco (
|
Warning.LargeAOA.str2 = Incontrato grande angolo d'attacco (
|
||||||
Warning.DISCONTINUITY = Discontinuita' nel diametro del tubo del corpo.
|
Warning.DISCONTINUITY = Discontinuita' nel diametro del tubo del corpo
|
||||||
Warning.THICK_FIN = Le pinne sottili potrebbero non essere modellate in modo accurato.
|
Warning.THICK_FIN = Le pinne sottili potrebbero non essere modellate in modo accurato.
|
||||||
Warning.JAGGED_EDGED_FIN = Jagged-edged fin Le predizioni per le pinne potrebbero non essere accurate.
|
Warning.JAGGED_EDGED_FIN = Jagged-edged fin Le predizioni per le pinne potrebbero non essere accurate.
|
||||||
Warning.LISTENERS_AFFECTED = Gli osservatori possono modificare le condizioni di simulazione
|
Warning.LISTENERS_AFFECTED = Gli osservatori possono modificare le condizioni di simulazione
|
||||||
|
|||||||
@ -1688,7 +1688,7 @@ PlotConfiguration.Groundtrack = Grondspoor
|
|||||||
! Warning
|
! Warning
|
||||||
Warning.LargeAOA.str1 = Grote invalshoek aangetroffen.
|
Warning.LargeAOA.str1 = Grote invalshoek aangetroffen.
|
||||||
Warning.LargeAOA.str2 = Grote invalshoek aangetroffen (
|
Warning.LargeAOA.str2 = Grote invalshoek aangetroffen (
|
||||||
Warning.DISCONTINUITY = Discontinuïteit in raketromp diameter.
|
Warning.DISCONTINUITY = Discontinuïteit in raketromp diameter
|
||||||
Warning.THICK_FIN = Dikke vinnen worden mogelijk niet nauwkeurig gemodelleerd.
|
Warning.THICK_FIN = Dikke vinnen worden mogelijk niet nauwkeurig gemodelleerd.
|
||||||
Warning.JAGGED_EDGED_FIN = De voorspellingen van gekartelde vinnen kunnen onnauwkeurig zijn.
|
Warning.JAGGED_EDGED_FIN = De voorspellingen van gekartelde vinnen kunnen onnauwkeurig zijn.
|
||||||
Warning.LISTENERS_AFFECTED = Luisteraars veranderden de vluchtsimulatie
|
Warning.LISTENERS_AFFECTED = Luisteraars veranderden de vluchtsimulatie
|
||||||
|
|||||||
@ -1319,7 +1319,7 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
|
|||||||
! Warning
|
! Warning
|
||||||
Warning.LargeAOA.str1 = Wyst\u0105pi\u0142 du\u017Cy k\u0105t natarcia.
|
Warning.LargeAOA.str1 = Wyst\u0105pi\u0142 du\u017Cy k\u0105t natarcia.
|
||||||
Warning.LargeAOA.str2 = Wyst\u0105pi\u0142 du\u017Cy k\u0105t natarcia (
|
Warning.LargeAOA.str2 = Wyst\u0105pi\u0142 du\u017Cy k\u0105t natarcia (
|
||||||
Warning.DISCONTINUITY = Nieci\u0105g\u0142o\u015B\u0107 \u015Brednicy rakiety.
|
Warning.DISCONTINUITY = Nieci\u0105g\u0142o\u015B\u0107 \u015Brednicy rakiety
|
||||||
Warning.THICK_FIN = Grube stateczniki mog\u0105 nie by\u0107 modelowane dok\u0142adnie.
|
Warning.THICK_FIN = Grube stateczniki mog\u0105 nie by\u0107 modelowane dok\u0142adnie.
|
||||||
Warning.JAGGED_EDGED_FIN = Stateczniki o nieregularnych kraw\u0119dziach mog\u0105 zmniejszy\u0107 dok\u0142adno\u015B\u0107 prognoz.
|
Warning.JAGGED_EDGED_FIN = Stateczniki o nieregularnych kraw\u0119dziach mog\u0105 zmniejszy\u0107 dok\u0142adno\u015B\u0107 prognoz.
|
||||||
Warning.LISTENERS_AFFECTED = Detektory zmodyfikowa\u0142y symulacj\u0119 lotu
|
Warning.LISTENERS_AFFECTED = Detektory zmodyfikowa\u0142y symulacj\u0119 lotu
|
||||||
|
|||||||
@ -1182,7 +1182,7 @@ TrapezoidFinSetCfg.tab.Generalproperties = Propriedades gerais
|
|||||||
# TubeCoupler
|
# TubeCoupler
|
||||||
TubeCoupler.TubeCoupler = Acoplador de tubo
|
TubeCoupler.TubeCoupler = Acoplador de tubo
|
||||||
|
|
||||||
Warning.DISCONTINUITY = Descontinuidade no di\u00e2metro do corpo do foguete.
|
Warning.DISCONTINUITY = Descontinuidade no di\u00e2metro do corpo do foguete
|
||||||
Warning.FILE_INVALID_PARAMETER = Par\u00e2metro inv\u00e1lido encontrado, ignorando.
|
Warning.FILE_INVALID_PARAMETER = Par\u00e2metro inv\u00e1lido encontrado, ignorando.
|
||||||
Warning.JAGGED_EDGED_FIN = Previs\u00f5es com aletas de bordo irregular podem ser imprecisos.
|
Warning.JAGGED_EDGED_FIN = Previs\u00f5es com aletas de bordo irregular podem ser imprecisos.
|
||||||
Warning.LISTENERS_AFFECTED = Observador modificou a simula\u00e7\u00e3o de voo
|
Warning.LISTENERS_AFFECTED = Observador modificou a simula\u00e7\u00e3o de voo
|
||||||
|
|||||||
@ -1535,7 +1535,7 @@ PlotConfiguration.Simulationtime = Simulation time step and computation time
|
|||||||
! Warning
|
! Warning
|
||||||
Warning.LargeAOA.str1 = Large angle of attack encountered.
|
Warning.LargeAOA.str1 = Large angle of attack encountered.
|
||||||
Warning.LargeAOA.str2 = Large angle of attack encountered (
|
Warning.LargeAOA.str2 = Large angle of attack encountered (
|
||||||
Warning.DISCONTINUITY = Discontinuity in rocket body diameter.
|
Warning.DISCONTINUITY = Discontinuity in rocket body diameter
|
||||||
Warning.THICK_FIN = Thick fins may not be modeled accurately.
|
Warning.THICK_FIN = Thick fins may not be modeled accurately.
|
||||||
Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate.
|
Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate.
|
||||||
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
|
||||||
|
|||||||
@ -1299,7 +1299,7 @@ TubeFinSetCfg.lbl.Outerdiam = \u5916\u76F4\u5F84:
|
|||||||
TubeFinSetCfg.lbl.Thickness = \u539A\u5EA6:
|
TubeFinSetCfg.lbl.Thickness = \u539A\u5EA6:
|
||||||
TubeFinSetCfg.lbl.ttip.Finrotation = \u7A33\u5B9A\u7FFC\u7EC4\u5408\u91CC\u7B2C\u4E00\u7247\u7684\u89D2\u5EA6
|
TubeFinSetCfg.lbl.ttip.Finrotation = \u7A33\u5B9A\u7FFC\u7EC4\u5408\u91CC\u7B2C\u4E00\u7247\u7684\u89D2\u5EA6
|
||||||
|
|
||||||
Warning.DISCONTINUITY = \u7BAD\u4F53\u76F4\u5F84\u4E0D\u8FDE\u7EED.
|
Warning.DISCONTINUITY = \u7BAD\u4F53\u76F4\u5F84\u4E0D\u8FDE\u7EED
|
||||||
Warning.FILE_INVALID_PARAMETER = \u65E0\u6548\u53C2\u6570, \u5FFD\u7565.
|
Warning.FILE_INVALID_PARAMETER = \u65E0\u6548\u53C2\u6570, \u5FFD\u7565.
|
||||||
Warning.JAGGED_EDGED_FIN = \u952F\u9F7F\u7FFC\u9884\u6D4B\u53EF\u80FD\u4E0D\u51C6\u786E.
|
Warning.JAGGED_EDGED_FIN = \u952F\u9F7F\u7FFC\u9884\u6D4B\u53EF\u80FD\u4E0D\u51C6\u786E.
|
||||||
Warning.LISTENERS_AFFECTED = \u76D1\u542C\u5668\u4FEE\u6539\u4E86\u98DE\u884C\u4EFF\u771F
|
Warning.LISTENERS_AFFECTED = \u76D1\u542C\u5668\u4FEE\u6539\u4E86\u98DE\u884C\u4EFF\u771F
|
||||||
|
|||||||
@ -68,5 +68,8 @@ public interface AerodynamicCalculator extends Monitorable {
|
|||||||
*/
|
*/
|
||||||
public AerodynamicCalculator newInstance();
|
public AerodynamicCalculator newInstance();
|
||||||
|
|
||||||
public boolean isContinuous(FlightConfiguration configuration, final Rocket rkt);
|
/**
|
||||||
|
* Test component assembly for continuity (esp. diameter), and post any needed warnings
|
||||||
|
*/
|
||||||
|
public void testIsContinuous(FlightConfiguration configuration, final RocketComponent component, WarningSet warnings);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -252,9 +252,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
if (calcMap == null)
|
if (calcMap == null)
|
||||||
buildCalcMap(configuration);
|
buildCalcMap(configuration);
|
||||||
|
|
||||||
if (!isContinuous(configuration, configuration.getRocket())){
|
testIsContinuous(configuration, configuration.getRocket(), warnings);
|
||||||
warnings.add( Warning.DIAMETER_DISCONTINUITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
final InstanceMap imap = configuration.getActiveInstances();
|
final InstanceMap imap = configuration.getActiveInstances();
|
||||||
|
|
||||||
@ -278,11 +276,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isContinuous(FlightConfiguration configuration, final Rocket rkt){
|
public void testIsContinuous(FlightConfiguration configuration, final RocketComponent treeRoot, WarningSet warnings ){
|
||||||
return testIsContinuous(configuration, rkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean testIsContinuous(FlightConfiguration configuration, final RocketComponent treeRoot ){
|
|
||||||
Queue<RocketComponent> queue = new LinkedList<>();
|
Queue<RocketComponent> queue = new LinkedList<>();
|
||||||
for (RocketComponent child : treeRoot.getChildren()) {
|
for (RocketComponent child : treeRoot.getChildren()) {
|
||||||
// Ignore inactive stages
|
// Ignore inactive stages
|
||||||
@ -292,9 +286,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
queue.add(child);
|
queue.add(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isContinuous = true;
|
|
||||||
SymmetricComponent prevComp = null;
|
SymmetricComponent prevComp = null;
|
||||||
while((isContinuous)&&( null != queue.peek())){
|
while(null != queue.peek()) {
|
||||||
RocketComponent comp = queue.poll();
|
RocketComponent comp = queue.poll();
|
||||||
if( comp instanceof SymmetricComponent ){
|
if( comp instanceof SymmetricComponent ){
|
||||||
for (RocketComponent child : comp.getChildren()) {
|
for (RocketComponent child : comp.getChildren()) {
|
||||||
@ -313,7 +306,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
|
|
||||||
// Check for radius discontinuity
|
// Check for radius discontinuity
|
||||||
if ( !MathUtil.equals(sym.getForeRadius(), prevComp.getAftRadius())) {
|
if ( !MathUtil.equals(sym.getForeRadius(), prevComp.getAftRadius())) {
|
||||||
isContinuous = false;
|
warnings.add( Warning.DIAMETER_DISCONTINUITY, sym + ", " + prevComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// double x = component.toAbsolute(Coordinate.NUL)[0].x;
|
// double x = component.toAbsolute(Coordinate.NUL)[0].x;
|
||||||
@ -327,11 +320,10 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
|
|
||||||
prevComp = sym;
|
prevComp = sym;
|
||||||
}else if( comp instanceof ComponentAssembly ){
|
}else if( comp instanceof ComponentAssembly ){
|
||||||
isContinuous &= testIsContinuous(configuration, comp);
|
testIsContinuous(configuration, comp, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return isContinuous;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,6 @@ public abstract class Warning {
|
|||||||
return new Warning.Other(text);
|
return new Warning.Other(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return <code>true</code> if the <code>other</code> warning should replace
|
* Return <code>true</code> if the <code>other</code> warning should replace
|
||||||
* this warning. The method should return <code>true</code> if the other
|
* this warning. The method should return <code>true</code> if the other
|
||||||
@ -398,4 +397,6 @@ public abstract class Warning {
|
|||||||
public static final Warning TUBE_OVERLAP = new Other(trans.get("Warning.TUBE_OVERLAP"));
|
public static final Warning TUBE_OVERLAP = new Other(trans.get("Warning.TUBE_OVERLAP"));
|
||||||
|
|
||||||
public static final Warning SEPARATION_ORDER = new Other(trans.get("Warning.SEPARATION_ORDER"));
|
public static final Warning SEPARATION_ORDER = new Other(trans.get("Warning.SEPARATION_ORDER"));
|
||||||
|
|
||||||
|
public static final Warning EMPTY_BRANCH = new Other(trans.get("Warning.EMPTY_BRANCH"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,6 +68,16 @@ public class WarningSet extends AbstractSet<Warning> implements Cloneable, Monit
|
|||||||
return add(Warning.fromString(s));
|
return add(Warning.fromString(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a <code>Warning</code> of the specified type with the specified discriminator to the
|
||||||
|
* set.
|
||||||
|
* @param w the warning
|
||||||
|
* @param d the extra discriminator
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean add (Warning w, String d) {
|
||||||
|
return this.add(w.toString() + ": " + d);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Warning> iterator() {
|
public Iterator<Warning> iterator() {
|
||||||
|
|||||||
@ -69,6 +69,9 @@ class ComponentPresetSetter implements Setter {
|
|||||||
warnings.add(Warning.fromString("ComponentPreset for component " + c.getName() + " has wrong digest"));
|
warnings.add(Warning.fromString("ComponentPreset for component " + c.getName() + " has wrong digest"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The preset loader can override the component name, so first store it and then apply it again
|
||||||
|
String componentName = c.getName();
|
||||||
setMethod.invoke(c, matchingPreset);
|
setMethod.invoke(c, matchingPreset);
|
||||||
|
c.setName(componentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
|
|||||||
* Maximum number of root points in the root geometry.
|
* Maximum number of root points in the root geometry.
|
||||||
*/
|
*/
|
||||||
private static final int MAX_ROOT_DIVISIONS = 100;
|
private static final int MAX_ROOT_DIVISIONS = 100;
|
||||||
private static final int MAX_ROOT_DIVISIONS_LOW_RES = 15;
|
private static final int MAX_ROOT_DIVISIONS_LOW_RES = MAX_ROOT_DIVISIONS / 5;
|
||||||
|
|
||||||
public void setOverrideMass() {
|
public void setOverrideMass() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package net.sf.openrocket.simulation;
|
package net.sf.openrocket.simulation;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -8,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import net.sf.openrocket.aerodynamics.Warning;
|
import net.sf.openrocket.aerodynamics.Warning;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
|
import net.sf.openrocket.motor.IgnitionEvent;
|
||||||
import net.sf.openrocket.motor.MotorConfiguration;
|
import net.sf.openrocket.motor.MotorConfiguration;
|
||||||
import net.sf.openrocket.motor.MotorConfigurationId;
|
import net.sf.openrocket.motor.MotorConfigurationId;
|
||||||
import net.sf.openrocket.rocketcomponent.AxialStage;
|
import net.sf.openrocket.rocketcomponent.AxialStage;
|
||||||
@ -68,11 +70,25 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
FlightConfiguration origConfig = simulationConditions.getRocket().getFlightConfiguration(this.fcid);
|
FlightConfiguration origConfig = simulationConditions.getRocket().getFlightConfiguration(this.fcid);
|
||||||
FlightConfiguration simulationConfig = origConfig.clone();
|
FlightConfiguration simulationConfig = origConfig.clone();
|
||||||
simulationConfig.copyStages(origConfig); // Clone the stage activation configuration
|
simulationConfig.copyStages(origConfig); // Clone the stage activation configuration
|
||||||
if ( ! simulationConfig.hasMotors() ) {
|
|
||||||
|
currentStatus = new SimulationStatus(simulationConfig, simulationConditions);
|
||||||
|
|
||||||
|
// Sanity checks on design and configuration
|
||||||
|
|
||||||
|
// Problems that keep us from simulating at all
|
||||||
|
|
||||||
|
// No motors in configuration
|
||||||
|
if (!simulationConfig.hasMotors() ) {
|
||||||
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
|
throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined"));
|
||||||
}
|
}
|
||||||
|
|
||||||
currentStatus = new SimulationStatus(simulationConfig, simulationConditions);
|
// Problems that let us simulate, but result is likely bad
|
||||||
|
|
||||||
|
// No recovery device
|
||||||
|
if (!simulationConfig.hasRecoveryDevice()) {
|
||||||
|
currentStatus.getWarnings().add(Warning.NO_RECOVERY_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
|
currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
|
||||||
{
|
{
|
||||||
// main simulation branch
|
// main simulation branch
|
||||||
@ -97,6 +113,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
dataBranch.getBranchName(),
|
dataBranch.getBranchName(),
|
||||||
currentStatus.getSimulationTime(),
|
currentStatus.getSimulationTime(),
|
||||||
dataBranch.getLast(FlightDataType.TYPE_TIME)));
|
dataBranch.getLast(FlightDataType.TYPE_TIME)));
|
||||||
|
|
||||||
|
|
||||||
|
// Did the branch generate any data?
|
||||||
|
if (dataBranch.getLength() == 0) {
|
||||||
|
flightData.getWarningSet().add(Warning.EMPTY_BRANCH, dataBranch.getBranchName());
|
||||||
|
}
|
||||||
}while( ! toSimulate.isEmpty());
|
}while( ! toSimulate.isEmpty());
|
||||||
|
|
||||||
SimulationListenerHelper.fireEndSimulation(currentStatus, null);
|
SimulationListenerHelper.fireEndSimulation(currentStatus, null);
|
||||||
@ -108,7 +130,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
return flightData;
|
return flightData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FlightDataBranch simulateLoop() {
|
private FlightDataBranch simulateLoop() throws SimulationException {
|
||||||
|
|
||||||
// Initialize the simulation. We'll use the flight stepper unless we're already on the ground
|
// Initialize the simulation. We'll use the flight stepper unless we're already on the ground
|
||||||
if (currentStatus.isLanded())
|
if (currentStatus.isLanded())
|
||||||
@ -240,9 +262,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
|
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
SimulationListenerHelper.fireEndSimulation(currentStatus, e);
|
SimulationListenerHelper.fireEndSimulation(currentStatus, e);
|
||||||
|
|
||||||
// Add FlightEvent for Abort.
|
// Add FlightEvent for Abort.
|
||||||
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
||||||
currentStatus.getWarnings().add(e.getLocalizedMessage());
|
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentStatus.getFlightData();
|
return currentStatus.getFlightData();
|
||||||
@ -342,11 +366,6 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a warning if there is no recovery device defined.
|
|
||||||
if (!currentStatus.getConfiguration().hasRecoveryDevice()) {
|
|
||||||
currentStatus.getWarnings().add(Warning.NO_RECOVERY_DEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle event
|
// Handle event
|
||||||
log.trace("Handling event " + event);
|
log.trace("Handling event " + event);
|
||||||
switch (event.getType()) {
|
switch (event.getType()) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package net.sf.openrocket.simulation.extension.impl;
|
package net.sf.openrocket.simulation.extension.impl;
|
||||||
|
|
||||||
|
import com.google.inject.ConfigurationException;
|
||||||
import net.sf.openrocket.simulation.SimulationConditions;
|
import net.sf.openrocket.simulation.SimulationConditions;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.extension.AbstractSimulationExtension;
|
import net.sf.openrocket.simulation.extension.AbstractSimulationExtension;
|
||||||
@ -23,11 +24,15 @@ public class JavaCode extends AbstractSimulationExtension {
|
|||||||
if (!SimulationListener.class.isAssignableFrom(clazz)) {
|
if (!SimulationListener.class.isAssignableFrom(clazz)) {
|
||||||
throw new SimulationException("Class " + className + " does not implement SimulationListener");
|
throw new SimulationException("Class " + className + " does not implement SimulationListener");
|
||||||
}
|
}
|
||||||
SimulationListener listener = (SimulationListener) injector.getInstance(clazz);
|
try {
|
||||||
conditions.getSimulationListenerList().add(listener);
|
SimulationListener listener = (SimulationListener) injector.getInstance(clazz);
|
||||||
|
conditions.getSimulationListenerList().add(listener);
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
throw new SimulationException(String.format(trans.get("SimulationExtension.javacode.couldnotinstantiate"), className), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new SimulationException("Could not find class " + className);
|
throw new SimulationException(trans.get("SimulationExtension.javacode.classnotfound") + " " + className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,10 @@ public class StopSimulationListener extends AbstractSimulationListener {
|
|||||||
private long startTime = -1;
|
private long startTime = -1;
|
||||||
private long time = -1;
|
private long time = -1;
|
||||||
|
|
||||||
|
public StopSimulationListener() {
|
||||||
|
this(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public StopSimulationListener(double t, int n) {
|
public StopSimulationListener(double t, int n) {
|
||||||
stopTime = t;
|
stopTime = t;
|
||||||
stopStep = n;
|
stopStep = n;
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
|
import net.sf.openrocket.util.StringUtil;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -671,7 +672,7 @@ public class UnitGroup {
|
|||||||
throw new NumberFormatException("string did not match required pattern");
|
throw new NumberFormatException("string did not match required pattern");
|
||||||
}
|
}
|
||||||
|
|
||||||
double value = Double.parseDouble(matcher.group(1));
|
double value = StringUtil.convertToDouble(matcher.group(1));
|
||||||
String unit = matcher.group(2).trim();
|
String unit = matcher.group(2).trim();
|
||||||
|
|
||||||
if (unit.equals("")) {
|
if (unit.equals("")) {
|
||||||
|
|||||||
@ -20,4 +20,23 @@ public class StringUtil {
|
|||||||
return "".equals(s.trim());
|
return "".equals(s.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string to a double, but with a more robust locale handling.
|
||||||
|
* Some systems use a comma as a decimal separator, some a dot. This method
|
||||||
|
* should work for both cases
|
||||||
|
* @param input string to convert
|
||||||
|
* @return double converted from string
|
||||||
|
* @throws NumberFormatException if the string cannot be parsed.
|
||||||
|
*/
|
||||||
|
public static double convertToDouble(String input) {
|
||||||
|
input = input.replace(',', '.');
|
||||||
|
int decimalSeparator = input.lastIndexOf('.');
|
||||||
|
|
||||||
|
if (decimalSeparator > -1) {
|
||||||
|
input = input.substring(0, decimalSeparator).replace(".", "") + input.substring(decimalSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Double.parseDouble(input);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -288,8 +288,10 @@ public class BarrowmanCalculatorTest {
|
|||||||
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||||
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
||||||
|
WarningSet warnings = new WarningSet();
|
||||||
|
|
||||||
assertTrue("Estes Alpha III should be continuous: ", calc.isContinuous(configuration, rocket));
|
calc.testIsContinuous(configuration, rocket, warnings);
|
||||||
|
assertTrue("Estes Alpha III should be continuous: ", warnings.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -297,8 +299,10 @@ public class BarrowmanCalculatorTest {
|
|||||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||||
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
||||||
|
WarningSet warnings = new WarningSet();
|
||||||
|
|
||||||
assertTrue("F9H should be continuous: ", calc.isContinuous(configuration, rocket));
|
calc.testIsContinuous(configuration, rocket, warnings);
|
||||||
|
assertTrue("F9H should be continuous: ", warnings.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -306,6 +310,7 @@ public class BarrowmanCalculatorTest {
|
|||||||
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||||
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
||||||
|
WarningSet warnings = new WarningSet();
|
||||||
|
|
||||||
NoseCone nose = (NoseCone)rocket.getChild(0).getChild(0);
|
NoseCone nose = (NoseCone)rocket.getChild(0).getChild(0);
|
||||||
BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
|
BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
|
||||||
@ -314,7 +319,8 @@ public class BarrowmanCalculatorTest {
|
|||||||
body.setOuterRadius( 0.012 );
|
body.setOuterRadius( 0.012 );
|
||||||
body.setName( body.getName()+" << discontinuous");
|
body.setName( body.getName()+" << discontinuous");
|
||||||
|
|
||||||
assertFalse(" Estes Alpha III has an undetected discontinuity:", calc.isContinuous(configuration, rocket));
|
calc.testIsContinuous(configuration, rocket, warnings);
|
||||||
|
assertFalse(" Estes Alpha III has an undetected discontinuity:", warnings.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -322,6 +328,7 @@ public class BarrowmanCalculatorTest {
|
|||||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||||
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
FlightConfiguration configuration = rocket.getSelectedConfiguration();
|
||||||
|
WarningSet warnings = new WarningSet();
|
||||||
|
|
||||||
final AxialStage coreStage = (AxialStage)rocket.getChild(1);
|
final AxialStage coreStage = (AxialStage)rocket.getChild(1);
|
||||||
final ParallelStage booster = (ParallelStage)coreStage.getChild(0).getChild(0);
|
final ParallelStage booster = (ParallelStage)coreStage.getChild(0).getChild(0);
|
||||||
@ -333,7 +340,8 @@ public class BarrowmanCalculatorTest {
|
|||||||
body.setOuterRadius( 0.012 );
|
body.setOuterRadius( 0.012 );
|
||||||
body.setName( body.getName()+" << discontinuous");
|
body.setName( body.getName()+" << discontinuous");
|
||||||
|
|
||||||
assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous(configuration, rocket));
|
calc.testIsContinuous(configuration, rocket, warnings);
|
||||||
|
assertFalse(" Missed discontinuity in Falcon 9 Heavy:" , warnings.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that tests
|
* A class that tests
|
||||||
@ -22,4 +23,25 @@ public class StringUtilTest {
|
|||||||
assertFalse(StringUtil.isEmpty("A"));
|
assertFalse(StringUtil.isEmpty("A"));
|
||||||
assertFalse(StringUtil.isEmpty(" . "));
|
assertFalse(StringUtil.isEmpty(" . "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertToDouble() {
|
||||||
|
assertEquals(0.2, StringUtil.convertToDouble(".2"), MathUtil.EPSILON);
|
||||||
|
assertEquals(0.2, StringUtil.convertToDouble(",2"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1, StringUtil.convertToDouble("1,"), MathUtil.EPSILON);
|
||||||
|
assertEquals(2, StringUtil.convertToDouble("2."), MathUtil.EPSILON);
|
||||||
|
assertEquals(1, StringUtil.convertToDouble("1"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1.52, StringUtil.convertToDouble("1.52"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1.52, StringUtil.convertToDouble("1,52"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1.5, StringUtil.convertToDouble("1.500"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1.5, StringUtil.convertToDouble("1,500"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500.61, StringUtil.convertToDouble("1.500,61"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500.61, StringUtil.convertToDouble("1,500.61"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500.2, StringUtil.convertToDouble("1,500,200"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500.2, StringUtil.convertToDouble("1.500.200"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500200.23, StringUtil.convertToDouble("1500200.23"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500200.23, StringUtil.convertToDouble("1500200,23"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500200.23, StringUtil.convertToDouble("1,500,200.23"), MathUtil.EPSILON);
|
||||||
|
assertEquals(1500200.23, StringUtil.convertToDouble("1.500.200,23"), MathUtil.EPSILON);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.EventObject;
|
import java.util.EventObject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
@ -26,16 +27,21 @@ import javax.swing.JFileChooser;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSeparator;
|
import javax.swing.JSeparator;
|
||||||
import javax.swing.JSpinner;
|
import javax.swing.JSpinner;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.event.ListSelectionEvent;
|
||||||
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
import net.sf.openrocket.gui.adaptors.CustomFocusTraversalPolicy;
|
import net.sf.openrocket.gui.adaptors.CustomFocusTraversalPolicy;
|
||||||
|
import net.sf.openrocket.gui.util.Icons;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -77,6 +83,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
|
|
||||||
private JTable table = null;
|
private JTable table = null;
|
||||||
private FinPointTableModel tableModel = null;
|
private FinPointTableModel tableModel = null;
|
||||||
|
private JPopupMenu pm;
|
||||||
|
|
||||||
private int dragIndex = -1;
|
private int dragIndex = -1;
|
||||||
private Point dragPoint = null;
|
private Point dragPoint = null;
|
||||||
@ -85,6 +92,9 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
private ScaleScrollPane figurePane = null;
|
private ScaleScrollPane figurePane = null;
|
||||||
private ScaleSelector selector;
|
private ScaleSelector selector;
|
||||||
|
|
||||||
|
private FinPointAction insertFinPointAction;
|
||||||
|
private FinPointAction deleteFinPointAction;
|
||||||
|
|
||||||
public FreeformFinSetConfig(OpenRocketDocument d, RocketComponent component, JDialog parent) {
|
public FreeformFinSetConfig(OpenRocketDocument d, RocketComponent component, JDialog parent) {
|
||||||
super(d, component, parent);
|
super(d, component, parent);
|
||||||
|
|
||||||
@ -246,11 +256,31 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
}
|
}
|
||||||
table.addMouseListener(new MouseAdapter() {
|
table.addMouseListener(new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent ev) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
int row = table.rowAtPoint(e.getPoint());
|
||||||
|
|
||||||
|
// Context menu on right-click
|
||||||
|
if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 1) {
|
||||||
|
// Select new row
|
||||||
|
if (!table.isRowSelected(row)) {
|
||||||
|
if (row >= 0 && row < table.getRowCount()) {
|
||||||
|
table.setRowSelectionInterval(row, row);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doPopup(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||||
|
@Override
|
||||||
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
figure.setSelectedIndex(table.getSelectedRow());
|
figure.setSelectedIndex(table.getSelectedRow());
|
||||||
figure.updateFigure();
|
figure.updateFigure();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
JScrollPane tablePane = new JScrollPane(table);
|
JScrollPane tablePane = new JScrollPane(table);
|
||||||
|
|
||||||
@ -265,6 +295,21 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Context menu for table
|
||||||
|
insertFinPointAction = new InsertPointAction();
|
||||||
|
deleteFinPointAction = new DeletePointAction();
|
||||||
|
pm = new JPopupMenu();
|
||||||
|
pm.add(insertFinPointAction);
|
||||||
|
pm.add(deleteFinPointAction);
|
||||||
|
|
||||||
|
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||||
|
@Override
|
||||||
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
|
updateActionStates();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// panel.add(new JLabel("Coordinates:"), "aligny bottom, alignx 50%");
|
// panel.add(new JLabel("Coordinates:"), "aligny bottom, alignx 50%");
|
||||||
// panel.add(new JLabel(" View:"), "wrap, aligny bottom");
|
// panel.add(new JLabel(" View:"), "wrap, aligny bottom");
|
||||||
|
|
||||||
@ -303,9 +348,11 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
panel.setLayout(new MigLayout("fill, gap 5!","", "[nogrid, fill, sizegroup display, growprio 200]5![sizegroup text, growprio 5]5![sizegroup buttons, align top, growprio 5]0!"));
|
panel.setLayout(new MigLayout("fill, gap 5!","", "[nogrid, fill, sizegroup display, growprio 200]5![sizegroup text, growprio 5]5![sizegroup buttons, align top, growprio 5]0!"));
|
||||||
|
|
||||||
// first row: main display
|
// first row: main display
|
||||||
panel.add(tablePane, "width 100lp:100lp:, growy");
|
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tablePane, figurePane);
|
||||||
|
splitPane.setResizeWeight(0.1);
|
||||||
|
splitPane.setBorder(null);
|
||||||
|
panel.add(splitPane, "width 300lp:500lp:, gap unrel, grow, height 100lp:250lp:, wrap");
|
||||||
order.add(table);
|
order.add(table);
|
||||||
panel.add(figurePane, "width 200lp:400lp:, gap unrel, grow, height 100lp:250lp:, wrap");
|
|
||||||
|
|
||||||
// row of text directly below figure
|
// row of text directly below figure
|
||||||
panel.add(new StyledLabel(trans.get("lbl.doubleClick1")+" "+trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "spanx 3");
|
panel.add(new StyledLabel(trans.get("lbl.doubleClick1")+" "+trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "spanx 3");
|
||||||
@ -415,6 +462,51 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new fin point between the currently selected point and the next point.
|
||||||
|
* The coordinates of the new point will be the average of the two points.
|
||||||
|
*/
|
||||||
|
private void insertPoint() {
|
||||||
|
int currentPointIdx = table.getSelectedRow();
|
||||||
|
if (currentPointIdx == -1 || currentPointIdx >= table.getRowCount() - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final FreeformFinSet finSet = (FreeformFinSet) component;
|
||||||
|
Coordinate currentPoint = finSet.getFinPoints()[currentPointIdx];
|
||||||
|
Coordinate nextPoint = finSet.getFinPoints()[currentPointIdx + 1];
|
||||||
|
Point2D.Double toAdd = new Point2D.Double((currentPoint.x + nextPoint.x) / 2, (currentPoint.y + nextPoint.y) / 2);
|
||||||
|
finSet.addPoint(currentPointIdx + 1, toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the currently selected fin point.
|
||||||
|
*/
|
||||||
|
private void deletePoint() {
|
||||||
|
int currentPointIdx = table.getSelectedRow();
|
||||||
|
if (currentPointIdx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final FreeformFinSet finSet = (FreeformFinSet) component;
|
||||||
|
try {
|
||||||
|
finSet.removePoint(currentPointIdx);
|
||||||
|
} catch (IllegalFinPointException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doPopup(MouseEvent e) {
|
||||||
|
pm.show(e.getComponent(), e.getX(), e.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateActionStates() {
|
||||||
|
if (insertFinPointAction == null) { // If one of the actions is null, the rest will be too
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertFinPointAction.updateEnabledState();
|
||||||
|
deleteFinPointAction.updateEnabledState();
|
||||||
|
}
|
||||||
|
|
||||||
private class FinPointScrollPane extends ScaleScrollPane {
|
private class FinPointScrollPane extends ScaleScrollPane {
|
||||||
|
|
||||||
private static final int ANY_MASK = (MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK | MouseEvent.META_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK | MouseEvent.SHIFT_DOWN_MASK);
|
private static final int ANY_MASK = (MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK | MouseEvent.META_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK | MouseEvent.SHIFT_DOWN_MASK);
|
||||||
@ -693,4 +785,46 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private abstract static class FinPointAction extends AbstractAction {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public abstract void updateEnabledState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InsertPointAction extends FinPointAction {
|
||||||
|
public InsertPointAction() {
|
||||||
|
putValue(NAME, trans.get("FreeformFinSetConfig.lbl.insertPoint"));
|
||||||
|
this.putValue(SMALL_ICON, Icons.FILE_NEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
insertPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateEnabledState() {
|
||||||
|
// You can't add to the last fin point
|
||||||
|
setEnabled(table.getSelectedRow() < table.getRowCount() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeletePointAction extends FinPointAction {
|
||||||
|
public DeletePointAction() {
|
||||||
|
putValue(NAME, trans.get("FreeformFinSetConfig.lbl.deletePoint"));
|
||||||
|
this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
deletePoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateEnabledState() {
|
||||||
|
// You can't delete the first or last fin point
|
||||||
|
setEnabled(table.getSelectedRow() > 0 && table.getSelectedRow() < table.getRowCount() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import net.sf.openrocket.util.Coordinate;
|
|||||||
import net.sf.openrocket.gui.figure3d.geometry.Geometry.Surface;
|
import net.sf.openrocket.gui.figure3d.geometry.Geometry.Surface;
|
||||||
|
|
||||||
public class FinRenderer {
|
public class FinRenderer {
|
||||||
private GLUtessellator tobj = GLU.gluNewTess();
|
private GLUtessellator tess = GLU.gluNewTess();
|
||||||
|
|
||||||
public void renderFinSet(final GL2 gl, FinSet finSet, Surface which) {
|
public void renderFinSet(final GL2 gl, FinSet finSet, Surface which) {
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ public class FinRenderer {
|
|||||||
GLUtessellatorCallback cb = new GLUtessellatorCallbackAdapter() {
|
GLUtessellatorCallback cb = new GLUtessellatorCallbackAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void vertex(Object vertexData) {
|
public void vertex(Object vertexData) {
|
||||||
double d[] = (double[]) vertexData;
|
double[] d = (double[]) vertexData;
|
||||||
gl.glTexCoord2d(d[0], d[1]);
|
gl.glTexCoord2d(d[0], d[1]);
|
||||||
gl.glVertex3dv(d, 0);
|
gl.glVertex3dv(d, 0);
|
||||||
}
|
}
|
||||||
@ -64,70 +64,83 @@ public class FinRenderer {
|
|||||||
public void end() {
|
public void end() {
|
||||||
gl.glEnd();
|
gl.glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) {
|
||||||
|
double[] vertex = new double[3];
|
||||||
|
vertex[0] = coords[0];
|
||||||
|
vertex[1] = coords[1];
|
||||||
|
vertex[2] = coords[2];
|
||||||
|
outData[0] = vertex;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GLU.gluTessCallback(tobj, GLU.GLU_TESS_VERTEX, cb);
|
GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, cb);
|
||||||
GLU.gluTessCallback(tobj, GLU.GLU_TESS_BEGIN, cb);
|
GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, cb);
|
||||||
GLU.gluTessCallback(tobj, GLU.GLU_TESS_END, cb);
|
GLU.gluTessCallback(tess, GLU.GLU_TESS_END, cb);
|
||||||
|
GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, cb);
|
||||||
|
|
||||||
// fin side: +z
|
// fin side: +z
|
||||||
if (finSet.getSpan() > 0 && finSet.getLength() > 0 && which == Surface.INSIDE) { // Right side
|
if (finSet.getSpan() > 0 && finSet.getLength() > 0 && which == Surface.INSIDE) { // Right side
|
||||||
GLU.gluTessBeginPolygon(tobj, null);
|
GLU.gluTessBeginPolygon(tess, null);
|
||||||
GLU.gluTessBeginContour(tobj);
|
GLU.gluTessBeginContour(tess);
|
||||||
gl.glNormal3f(0, 0, 1);
|
gl.glNormal3f(0, 0, 1);
|
||||||
for (int i = finPoints.length - 1; i >= 0; i--) {
|
for (int i = finPoints.length - 1; i >= 0; i--) {
|
||||||
Coordinate c = finPoints[i];
|
Coordinate c = finPoints[i];
|
||||||
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
||||||
c.z + finSet.getThickness() / 2.0};
|
c.z + finSet.getThickness() / 2.0};
|
||||||
GLU.gluTessVertex(tobj, p, 0, p);
|
GLU.gluTessVertex(tess, p, 0, p);
|
||||||
}
|
}
|
||||||
GLU.gluTessEndContour(tobj);
|
GLU.gluTessEndContour(tess);
|
||||||
GLU.gluTessEndPolygon(tobj);
|
GLU.gluTessEndPolygon(tess);
|
||||||
}
|
}
|
||||||
// tab side: +z
|
// tab side: +z
|
||||||
if (finSet.getTabHeight() > 0 && finSet.getTabLength() > 0 && which == Surface.INSIDE) { // Right side
|
if (finSet.getTabHeight() > 0 && finSet.getTabLength() > 0 && which == Surface.INSIDE) { // Right side
|
||||||
GLU.gluTessBeginPolygon(tobj, null);
|
GLU.gluTessBeginPolygon(tess, null);
|
||||||
GLU.gluTessBeginContour(tobj);
|
GLU.gluTessBeginContour(tess);
|
||||||
gl.glNormal3f(0, 0, 1);
|
gl.glNormal3f(0, 0, 1);
|
||||||
for (int i = tabPoints.length - 1; i >= 0; i--) {
|
for (int i = tabPoints.length - 1; i >= 0; i--) {
|
||||||
Coordinate c = tabPoints[i];
|
Coordinate c = tabPoints[i];
|
||||||
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
||||||
c.z + finSet.getThickness() / 2.0};
|
c.z + finSet.getThickness() / 2.0};
|
||||||
GLU.gluTessVertex(tobj, p, 0, p);
|
GLU.gluTessVertex(tess, p, 0, p);
|
||||||
}
|
}
|
||||||
GLU.gluTessEndContour(tobj);
|
GLU.gluTessEndContour(tess);
|
||||||
GLU.gluTessEndPolygon(tobj);
|
GLU.gluTessEndPolygon(tess);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fin side: -z
|
// fin side: -z
|
||||||
if (finSet.getSpan() > 0 && finSet.getLength() > 0 && which == Surface.OUTSIDE) { // Left side
|
if (finSet.getSpan() > 0 && finSet.getLength() > 0 && which == Surface.OUTSIDE) { // Left side
|
||||||
GLU.gluTessBeginPolygon(tobj, null);
|
GLU.gluTessBeginPolygon(tess, null);
|
||||||
GLU.gluTessBeginContour(tobj);
|
GLU.gluTessBeginContour(tess);
|
||||||
gl.glNormal3f(0, 0, -1);
|
gl.glNormal3f(0, 0, -1);
|
||||||
for (Coordinate c : finPoints) {
|
for (Coordinate c : finPoints) {
|
||||||
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
||||||
c.z - finSet.getThickness() / 2.0};
|
c.z - finSet.getThickness() / 2.0};
|
||||||
GLU.gluTessVertex(tobj, p, 0, p);
|
GLU.gluTessVertex(tess, p, 0, p);
|
||||||
|
|
||||||
}
|
}
|
||||||
GLU.gluTessEndContour(tobj);
|
GLU.gluTessEndContour(tess);
|
||||||
GLU.gluTessEndPolygon(tobj);
|
GLU.gluTessEndPolygon(tess);
|
||||||
}
|
}
|
||||||
// tab side: -z
|
// tab side: -z
|
||||||
if (finSet.getTabHeight() > 0 && finSet.getTabLength() > 0 && which == Surface.OUTSIDE) { // Left side
|
if (finSet.getTabHeight() > 0 && finSet.getTabLength() > 0 && which == Surface.OUTSIDE) { // Left side
|
||||||
GLU.gluTessBeginPolygon(tobj, null);
|
GLU.gluTessBeginPolygon(tess, null);
|
||||||
GLU.gluTessBeginContour(tobj);
|
GLU.gluTessBeginContour(tess);
|
||||||
gl.glNormal3f(0, 0, -1);
|
gl.glNormal3f(0, 0, -1);
|
||||||
for (Coordinate c : tabPoints) {
|
for (Coordinate c : tabPoints) {
|
||||||
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
double[] p = new double[]{c.x, c.y + finSet.getBodyRadius(),
|
||||||
c.z - finSet.getThickness() / 2.0};
|
c.z - finSet.getThickness() / 2.0};
|
||||||
GLU.gluTessVertex(tobj, p, 0, p);
|
GLU.gluTessVertex(tess, p, 0, p);
|
||||||
|
|
||||||
}
|
}
|
||||||
GLU.gluTessEndContour(tobj);
|
GLU.gluTessEndContour(tess);
|
||||||
GLU.gluTessEndPolygon(tobj);
|
GLU.gluTessEndPolygon(tess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete tessellator after processing
|
||||||
|
GLU.gluDeleteTess(tess);
|
||||||
|
|
||||||
// Fin strip around the edge
|
// Fin strip around the edge
|
||||||
if (finSet.getSpan() > 0 && finSet.getLength() > 0 && which == Surface.EDGES) {
|
if (finSet.getSpan() > 0 && finSet.getLength() > 0 && which == Surface.EDGES) {
|
||||||
if (!(finSet instanceof EllipticalFinSet))
|
if (!(finSet instanceof EllipticalFinSet))
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package net.sf.openrocket.gui.main;
|
package net.sf.openrocket.gui.main;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
@ -20,7 +22,25 @@ import java.util.Arrays;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import javax.swing.*;
|
import javax.swing.Action;
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuBar;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JSpinner;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
|
import javax.swing.JTabbedPane;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.border.BevelBorder;
|
import javax.swing.border.BevelBorder;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.tree.DefaultTreeSelectionModel;
|
import javax.swing.tree.DefaultTreeSelectionModel;
|
||||||
@ -259,11 +279,13 @@ public class BasicFrame extends JFrame {
|
|||||||
if( componentSelectionModel.isSelectionEmpty() ){
|
if( componentSelectionModel.isSelectionEmpty() ){
|
||||||
final Rocket rocket = document.getRocket();
|
final Rocket rocket = document.getRocket();
|
||||||
if( rocket != null ) {
|
if( rocket != null ) {
|
||||||
final AxialStage topStage = (AxialStage) rocket.getChild(0);
|
final RocketComponent topStage = rocket.getChild(0);
|
||||||
if (topStage != null) {
|
if (topStage != null) {
|
||||||
final TreePath selectionPath = new TreePath(topStage);
|
final TreePath selectionPath = new TreePath(topStage);
|
||||||
componentSelectionModel.setSelectionPath(selectionPath);
|
componentSelectionModel.setSelectionPath(selectionPath);
|
||||||
tree.setSelectionRow(1);
|
tree.setSelectionRow(1);
|
||||||
|
// Don't select children components at startup (so override the default behavior with this new selection)
|
||||||
|
rocketpanel.getFigure().setSelection(new RocketComponent[] { topStage });
|
||||||
log.debug("... Setting Initial Selection: " + tree.getSelectionPath() );
|
log.debug("... Setting Initial Selection: " + tree.getSelectionPath() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,36 +69,30 @@ public class DesignPanel extends JSplitPane {
|
|||||||
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, SHORTCUT_KEY), null);
|
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, SHORTCUT_KEY), null);
|
||||||
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, SHORTCUT_KEY), null);
|
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, SHORTCUT_KEY), null);
|
||||||
|
|
||||||
// Visually select all child components of a stage/rocket/podset when it is selected
|
// Highlight all child components of a stage/rocket/podset when it is selected
|
||||||
tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void valueChanged(TreeSelectionEvent e) {
|
public void valueChanged(TreeSelectionEvent e) {
|
||||||
if (tree == null || tree.getSelectionPaths() == null || tree.getSelectionPaths().length == 0
|
highlightAssemblyChildren(tree, parent);
|
||||||
|| parent.getRocketPanel() == null) return;
|
|
||||||
|
|
||||||
// Get all the components that need to be selected = currently selected components + children of stages/boosters/podsets
|
|
||||||
List<RocketComponent> children = new ArrayList<>(Arrays.asList(parent.getRocketPanel().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 (parent.getRocketPanel().getFigure() != null && parent.getRocketPanel().getFigure3d() != null) {
|
|
||||||
parent.getRocketPanel().getFigure().setSelection(children.toArray(new RocketComponent[0]));
|
|
||||||
parent.getRocketPanel().getFigure3d().setSelection(children.toArray(new RocketComponent[0]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add a mouse listener for when the sustainer is selected at startup, to ensure that its children are highlighted.
|
||||||
|
// This is necessary because we force the children to not be highlighted when the tree is first created, and
|
||||||
|
// re-clicking the sustainer would not fire a change event in the tree (which normally highlights the children).
|
||||||
|
MouseAdapter mouseAdapter = new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (tree.getSelectionPath() != null &&
|
||||||
|
tree.getSelectionPath().getLastPathComponent() == document.getRocket().getChild(0)) {
|
||||||
|
highlightAssemblyChildren(tree, parent);
|
||||||
|
}
|
||||||
|
// Delete the listener again. We only need it at start-up, i.e. when the first click is registered.
|
||||||
|
tree.removeMouseListener(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tree.addMouseListener(mouseAdapter);
|
||||||
|
|
||||||
// Double-click opens config dialog
|
// Double-click opens config dialog
|
||||||
MouseListener ml = new MouseAdapter() {
|
MouseListener ml = new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@ -234,6 +228,37 @@ public class DesignPanel extends JSplitPane {
|
|||||||
this.setRightComponent(panel);
|
this.setRightComponent(panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlight all child components of a stage/rocket/podset when it is selected
|
||||||
|
* @param tree the tree in which the component selection took place
|
||||||
|
* @param parent the parent frame to highlight the components in
|
||||||
|
*/
|
||||||
|
private static void highlightAssemblyChildren(ComponentTree tree, BasicFrame parent) {
|
||||||
|
if (tree == null || tree.getSelectionPaths() == null || tree.getSelectionPaths().length == 0
|
||||||
|
|| parent.getRocketPanel() == null) return;
|
||||||
|
|
||||||
|
// Get all the components that need to be selected = currently selected components + children of stages/boosters/podsets
|
||||||
|
List<RocketComponent> children = new ArrayList<>(Arrays.asList(parent.getRocketPanel().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 (parent.getRocketPanel().getFigure() != null && parent.getRocketPanel().getFigure3d() != null) {
|
||||||
|
parent.getRocketPanel().getFigure().setSelection(children.toArray(new RocketComponent[0]));
|
||||||
|
parent.getRocketPanel().getFigure3d().setSelection(children.toArray(new RocketComponent[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focus on the component tree.
|
* Focus on the component tree.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -208,13 +208,10 @@ public class SimulationPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
// Show context menu
|
// Show context menu
|
||||||
else if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 1) {
|
else if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 1) {
|
||||||
// Get the row that the right-click action happened on
|
|
||||||
int r = simulationTable.rowAtPoint(e.getPoint());
|
|
||||||
|
|
||||||
// Select new row
|
// Select new row
|
||||||
if (!simulationTable.isRowSelected(r)) {
|
if (!simulationTable.isRowSelected(row)) {
|
||||||
if (r >= 0 && r < simulationTable.getRowCount()) {
|
if (row >= 0 && row < simulationTable.getRowCount()) {
|
||||||
simulationTable.setRowSelectionInterval(r, r);
|
simulationTable.setRowSelectionInterval(row, row);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,6 @@ import net.sf.openrocket.simulation.FlightDataType;
|
|||||||
import net.sf.openrocket.simulation.FlightEvent;
|
import net.sf.openrocket.simulation.FlightEvent;
|
||||||
import net.sf.openrocket.unit.Unit;
|
import net.sf.openrocket.unit.Unit;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
|
||||||
import net.sf.openrocket.util.LinearInterpolator;
|
import net.sf.openrocket.util.LinearInterpolator;
|
||||||
|
|
||||||
import net.sf.openrocket.utils.DecimalFormatter;
|
import net.sf.openrocket.utils.DecimalFormatter;
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import java.awt.BorderLayout;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.InputEvent;
|
import java.awt.event.InputEvent;
|
||||||
@ -16,7 +15,6 @@ import java.util.EventListener;
|
|||||||
import java.util.EventObject;
|
import java.util.EventObject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|||||||
@ -209,12 +209,10 @@ public class SimulationEditDialog extends JDialog {
|
|||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
copyChangesToAllSims();
|
copyChangesToAllSims();
|
||||||
SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulationList);
|
SimulationRunDialog dialog = SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulationList);
|
||||||
refreshView();
|
if (allowsPlotMode() && dialog.isAllSimulationsSuccessful()) {
|
||||||
if (allowsPlotMode()) {
|
refreshView();
|
||||||
setPlotMode();
|
setPlotMode();
|
||||||
} else {
|
|
||||||
setVisible(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -237,6 +237,7 @@ class SimulationOptionsPanel extends JPanel {
|
|||||||
SwingSimulationExtensionConfigurator configurator = findConfigurator(e);
|
SwingSimulationExtensionConfigurator configurator = findConfigurator(e);
|
||||||
if (configurator != null) {
|
if (configurator != null) {
|
||||||
configurator.configure(e, simulation, SwingUtilities.windowForComponent(SimulationOptionsPanel.this));
|
configurator.configure(e, simulation, SwingUtilities.windowForComponent(SimulationOptionsPanel.this));
|
||||||
|
updateCurrentExtensions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -281,6 +282,7 @@ class SimulationOptionsPanel extends JPanel {
|
|||||||
SwingSimulationExtensionConfigurator configurator = findConfigurator(e);
|
SwingSimulationExtensionConfigurator configurator = findConfigurator(e);
|
||||||
if (configurator != null) {
|
if (configurator != null) {
|
||||||
configurator.configure(e, simulation, SwingUtilities.windowForComponent(SimulationOptionsPanel.this));
|
configurator.configure(e, simulation, SwingUtilities.windowForComponent(SimulationOptionsPanel.this));
|
||||||
|
updateCurrentExtensions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -23,6 +23,8 @@ import javax.swing.JOptionPane;
|
|||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JProgressBar;
|
import javax.swing.JProgressBar;
|
||||||
|
|
||||||
|
import net.sf.openrocket.document.events.DocumentChangeEvent;
|
||||||
|
import net.sf.openrocket.document.events.SimulationChangeEvent;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -207,9 +209,12 @@ public class SimulationRunDialog extends JDialog {
|
|||||||
* the parent Window of the dialog to use.
|
* the parent Window of the dialog to use.
|
||||||
* @param simulations
|
* @param simulations
|
||||||
* the simulations to run.
|
* the simulations to run.
|
||||||
|
* @return the simulation run dialog instance.
|
||||||
*/
|
*/
|
||||||
public static void runSimulations(Window parent, OpenRocketDocument document, Simulation... simulations) {
|
public static SimulationRunDialog runSimulations(Window parent, OpenRocketDocument document, Simulation... simulations) {
|
||||||
new SimulationRunDialog(parent, document, simulations).setVisible(true);
|
SimulationRunDialog dialog = new SimulationRunDialog(parent, document, simulations);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProgress() {
|
private void updateProgress() {
|
||||||
@ -257,6 +262,18 @@ public class SimulationRunDialog extends JDialog {
|
|||||||
+ u.toStringUnit(simulationMaxVelocity[index]) + ")");
|
+ u.toStringUnit(simulationMaxVelocity[index]) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if all the simulations ran successfully. Returns false if the simulations encountered
|
||||||
|
* an exception, or were cancelled.
|
||||||
|
*/
|
||||||
|
public boolean isAllSimulationsSuccessful() {
|
||||||
|
for (SimulationWorker w : simulationWorkers) {
|
||||||
|
if (w.getThrowable() != null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SwingWorker that performs a flight simulation. It periodically updates
|
* A SwingWorker that performs a flight simulation. It periodically updates
|
||||||
* the simulation statuses of the parent class and calls updateProgress().
|
* the simulation statuses of the parent class and calls updateProgress().
|
||||||
@ -273,6 +290,7 @@ public class SimulationRunDialog extends JDialog {
|
|||||||
private volatile double apogeeAltitude;
|
private volatile double apogeeAltitude;
|
||||||
|
|
||||||
private final CustomExpressionSimulationListener exprListener;
|
private final CustomExpressionSimulationListener exprListener;
|
||||||
|
private final OpenRocketDocument document;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep track of current phase ("stage") of simulation
|
* Keep track of current phase ("stage") of simulation
|
||||||
@ -287,7 +305,8 @@ public class SimulationRunDialog extends JDialog {
|
|||||||
|
|
||||||
public InteractiveSimulationWorker(OpenRocketDocument doc, Simulation sim, int index) {
|
public InteractiveSimulationWorker(OpenRocketDocument doc, Simulation sim, int index) {
|
||||||
super(sim);
|
super(sim);
|
||||||
List<CustomExpression> exprs = doc.getCustomExpressions();
|
this.document = doc;
|
||||||
|
List<CustomExpression> exprs = document.getCustomExpressions();
|
||||||
exprListener = new CustomExpressionSimulationListener(exprs);
|
exprListener = new CustomExpressionSimulationListener(exprs);
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
|
||||||
@ -389,6 +408,7 @@ public class SimulationRunDialog extends JDialog {
|
|||||||
log.debug("Simulation done");
|
log.debug("Simulation done");
|
||||||
setSimulationProgress(1.0);
|
setSimulationProgress(1.0);
|
||||||
updateProgress();
|
updateProgress();
|
||||||
|
document.fireDocumentChangeEvent(new SimulationChangeEvent(simulation));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -71,6 +71,17 @@ public abstract class SimulationWorker extends SwingWorker<FlightData, Simulatio
|
|||||||
return new SimulationListener[0];
|
return new SimulationListener[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the throwable that caused the simulation to fail or cancel,
|
||||||
|
* or null if the simulation ran successfully.
|
||||||
|
*
|
||||||
|
* @return throwable that caused the simulation to fail or cancel,
|
||||||
|
* or null if the simulation ran successfully.
|
||||||
|
*/
|
||||||
|
public Throwable getThrowable() {
|
||||||
|
return throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after a simulation is successfully simulated. This method is not
|
* Called after a simulation is successfully simulated. This method is not
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import java.awt.Dialog.ModalityType;
|
|||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
@ -50,17 +52,21 @@ public abstract class AbstractSwingSimulationExtensionConfigurator<E extends Sim
|
|||||||
close.addActionListener(new ActionListener() {
|
close.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
dialog.setVisible(false);
|
close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
panel.add(close, "right");
|
panel.add(close, "right");
|
||||||
|
|
||||||
|
dialog.addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
dialog.add(panel);
|
dialog.add(panel);
|
||||||
GUIUtil.setDisposableDialogOptions(dialog, close);
|
GUIUtil.setDisposableDialogOptions(dialog, close);
|
||||||
dialog.setVisible(true);
|
dialog.setVisible(true);
|
||||||
close();
|
|
||||||
GUIUtil.setNullModels(dialog);
|
|
||||||
dialog = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,10 +84,12 @@ public abstract class AbstractSwingSimulationExtensionConfigurator<E extends Sim
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the default dialog is closed. By default does nothing.
|
* Called when the default dialog is closed. By default hides the dialog and cleans up the component models.
|
||||||
*/
|
*/
|
||||||
protected void close() {
|
protected void close() {
|
||||||
|
dialog.setVisible(false);
|
||||||
|
GUIUtil.setNullModels(dialog);
|
||||||
|
dialog = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract JComponent getConfigurationComponent(E extension, Simulation simulation, JPanel panel);
|
protected abstract JComponent getConfigurationComponent(E extension, Simulation simulation, JPanel panel);
|
||||||
|
|||||||
@ -8,11 +8,20 @@ import javax.swing.event.DocumentEvent;
|
|||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.plugin.Plugin;
|
import net.sf.openrocket.plugin.Plugin;
|
||||||
import net.sf.openrocket.simulation.extension.AbstractSwingSimulationExtensionConfigurator;
|
import net.sf.openrocket.simulation.extension.AbstractSwingSimulationExtensionConfigurator;
|
||||||
|
import net.sf.openrocket.startup.Application;
|
||||||
|
import net.sf.openrocket.util.Color;
|
||||||
|
|
||||||
@Plugin
|
@Plugin
|
||||||
public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfigurator<JavaCode> {
|
public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfigurator<JavaCode> {
|
||||||
|
private JavaCode extension;
|
||||||
|
private JTextField classNameField;
|
||||||
|
private StyledLabel errorMsg;
|
||||||
|
|
||||||
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
public JavaCodeConfigurator() {
|
public JavaCodeConfigurator() {
|
||||||
super(JavaCode.class);
|
super(JavaCode.class);
|
||||||
@ -20,10 +29,17 @@ public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JComponent getConfigurationComponent(final JavaCode extension, Simulation simulation, JPanel panel) {
|
protected JComponent getConfigurationComponent(final JavaCode extension, Simulation simulation, JPanel panel) {
|
||||||
|
this.extension = extension;
|
||||||
panel.add(new JLabel(trans.get("SimulationExtension.javacode.desc")), "wrap para");
|
panel.add(new JLabel(trans.get("SimulationExtension.javacode.desc")), "wrap para");
|
||||||
panel.add(new JLabel(trans.get("SimulationExtension.javacode.className")), "wrap rel");
|
panel.add(new JLabel(trans.get("SimulationExtension.javacode.className")), "wrap rel");
|
||||||
final JTextField textField = new JTextField(extension.getClassName());
|
classNameField = new JTextField(extension.getClassName());
|
||||||
textField.getDocument().addDocumentListener(new DocumentListener() {
|
panel.add(classNameField, "growx, wrap");
|
||||||
|
this.errorMsg = new StyledLabel();
|
||||||
|
errorMsg.setFontColor(Color.DARK_RED.toAWTColor());
|
||||||
|
errorMsg.setVisible(false);
|
||||||
|
panel.add(errorMsg, "growx, wrap");
|
||||||
|
|
||||||
|
classNameField.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
public void changedUpdate(DocumentEvent e) {
|
public void changedUpdate(DocumentEvent e) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -37,11 +53,41 @@ public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
extension.setClassName(textField.getText());
|
updateErrorMsg();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
panel.add(textField, "growx");
|
updateErrorMsg();
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateErrorMsg() {
|
||||||
|
if (this.errorMsg == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Display error message if the class name is invalid
|
||||||
|
String text = classNameField.getText().trim();
|
||||||
|
try {
|
||||||
|
Class.forName(text);
|
||||||
|
errorMsg.setVisible(false);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
// Don't display an error message for an empty field
|
||||||
|
if (text.length() == 0) {
|
||||||
|
errorMsg.setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorMsg.setText(trans.get("SimulationExtension.javacode.classnotfound"));
|
||||||
|
errorMsg.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void close() {
|
||||||
|
if (this.extension != null && this.classNameField != null) {
|
||||||
|
this.extension.setClassName(this.classNameField.getText().trim());
|
||||||
|
|
||||||
|
}
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user