diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 52354cb41..24f918dbf 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -452,12 +452,10 @@ simedtdlg.but.delete = Delete
simedtdlg.title.Editsim = Edit simulation
simedtdlg.title.MultiSimEdit = Multi-simulation edit
simedtdlg.title.MultiSimEdit.ttip = You are editing the following simulations:
-simedtdlg.lbl.Simname = Simulation name:
+simedtdlg.lbl.Simname = Name:
simedtdlg.tab.Launchcond = Launch conditions
simedtdlg.tab.Simopt = Simulation options
-simedtdlg.tab.Plotdata = Plot data
simedtdlg.tab.CustomExpressions = Custom expressions
-simedtdlg.tab.Exportdata = Export data
simedtdlg.lbl.Flightcfg = Flight configuration:
simedtdlg.lbl.ttip.Flightcfg = Select the flight configuration to use.
simedtdlg.combo.ttip.Flightcfg = Select the flight configuration to use.
@@ -534,6 +532,30 @@ simedtdlg.IntensityDesc.High = High
simedtdlg.IntensityDesc.Veryhigh = Very high
simedtdlg.IntensityDesc.Extreme = Extreme
+! SimulationConfigDialog
+SimulationConfigDialog.tab.Settings = Settings
+SimulationConfigDialog.tab.Warnings = Warnings
+SimulationConfigDialog.tab.Plotdata = Plot data
+SimulationConfigDialog.tab.Exportdata = Export data
+SimulationConfigDialog.btn.plot = Plot
+SimulationConfigDialog.btn.export = Export
+SimulationConfigDialog.btn.OK.ttip = Keep changes and close the dialog
+SimulationConfigDialog.btn.Cancel.ttip = Discard changes and close the dialog
+SimulationConfigDialog.CancelOperation.msg.discardChanges = Are you sure you want to discard your changes to this simulation?
+SimulationConfigDialog.CancelOperation.msg.undoAdd = Are you sure you want to undo adding this simulation?
+SimulationConfigDialog.CancelOperation.title = Cancel operation
+SimulationConfigDialog.CancelOperation.checkbox.dontAskAgain = Don't ask me again
+SimulationConfigDialog.tab.warnDis.ttip = Warnings not supported for multi-simulation editing
+SimulationConfigDialog.tab.plotDis.ttip = Plotting not supported for multi-simulation editing
+SimulationConfigDialog.tab.plotNoData.ttip = Simulation has no data to plot
+SimulationConfigDialog.tab.expDis.ttip = Exporting not supported for multi-simulation editing
+SimulationConfigDialog.tab.expNoData.ttip = Simulation has no data to export
+
+! SimulationWarningsPanel
+SimulationWarningsPanel.lbl.CriticalWarnings = Critical Warning(s)
+SimulationWarningsPanel.lbl.NormalWarnings = Warning(s)
+SimulationWarningsPanel.lbl.InformativeWarnings = Informative Warning(s)
+
SimulationExtension.airstart.name.alt = Air-start ({alt})
SimulationExtension.airstart.name.altvel = Air-start ({alt}, {vel})
SimulationExtension.javacode.name = Java code
@@ -556,18 +578,6 @@ SimulationExtension.scripting.text.trusted.clear.ttip = Clear the trusted status
SimulationExtension.scripting.text.trusted.cleared = All scripts are now untrusted on this computer.
SimulationExtension.scripting.text.trusted.cleared.title = Cleared
-SimulationEditDialog.btn.plot = Plot
-SimulationEditDialog.btn.export = Export
-SimulationEditDialog.btn.edit = Edit
-SimulationEditDialog.btn.simulate = Simulate
-SimulationEditDialog.btn.simulateAndPlot = Simulate & Plot
-SimulationEditDialog.btn.OK.ttip = Keep changes and close the dialog
-SimulationEditDialog.btn.Cancel.ttip = Discard changes and close the dialog
-SimulationEditDialog.CancelOperation.msg.discardChanges = Are you sure you want to discard your changes to this simulation?
-SimulationEditDialog.CancelOperation.msg.undoAdd = Are you sure you want to undo adding this simulation?
-SimulationEditDialog.CancelOperation.title = Cancel operation
-SimulationEditDialog.CancelOperation.checkbox.dontAskAgain = Don't ask me again
-
GeodeticComputationStrategy.flat.name = Flat Earth
GeodeticComputationStrategy.flat.desc = Perform computations with a flat Earth approximation. Sufficient for low-altitude flights.
GeodeticComputationStrategy.spherical.name = Spherical approximation
@@ -614,6 +624,7 @@ simpanel.dlg.lbl.DeleteSim1 = Delete the selected simulations?
simpanel.dlg.lbl.DeleteSim2 = This operation cannot be undone.
simpanel.dlg.lbl.DeleteSim3 = Delete simulations
simpanel.col.Status = Status
+simpanel.col.Warnings = Warnings
simpanel.col.Name = Name
simpanel.col.Motors = Motors
simpanel.col.Configuration = Configuration
@@ -633,8 +644,10 @@ simpanel.ttip.outdated = Out of date
Click
simpanel.ttip.external = Imported data
simpanel.ttip.notSimulated = Not simulated yet
Click Run simulations to simulate.
simpanel.ttip.noData = No simulation data available.
-simpanel.ttip.noWarnings = No warnings.
-simpanel.ttip.warnings = Warnings:
+simpanel.ttip.noWarnings = No warnings.
+simpanel.ttip.criticalWarnings = Critical Warnings:
+simpanel.ttip.normalWarnings = Warnings:
+simpanel.ttip.informativeWarnings = Informative:
simpanel.ttip.simAbort = Simulation Abort
simpanel.msg.invalidCopySelection = Invalid copy selection
@@ -2156,11 +2169,11 @@ Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING =
Warning.FILE_INVALID_PARAMETER = Invalid parameter encountered, ignoring.
Warning.PARALLEL_FINS = Too many parallel fins
Warning.SUPERSONIC = Body calculations may not be entirely accurate at supersonic speeds.
-Warning.RECOVERY_LAUNCH_ROD = Recovery device device deployed while on the launch guide.
+Warning.RECOVERY_LAUNCH_ROD = Recovery device deployed while on the launch guide.
Warning.RECOVERY_HIGH_SPEED = Recovery device deployment at high speed
Warning.NO_RECOVERY_DEVICE = No recovery device defined in the simulation.
Warning.TUMBLE_UNDER_THRUST = Stage began to tumble under thrust.
-Warning.EVENT_AFTER_LANDING = Flight Event occurred after landing:
+Warning.EVENT_AFTER_LANDING = Flight Event occurred after landing:
Warning.ZERO_VOLUME_BODY = Zero-volume bodies may not simulate accurately
Warning.TUBE_SEPARATION = Space between tube fins may not simulate accurately.
Warning.TUBE_OVERLAP = Overlapping tube fins may not simulate accurately.
diff --git a/core/resources/l10n/messages_ar.properties b/core/resources/l10n/messages_ar.properties
index 10b0700d2..8aba2669c 100644
--- a/core/resources/l10n/messages_ar.properties
+++ b/core/resources/l10n/messages_ar.properties
@@ -385,9 +385,9 @@ simedtdlg.title.Editsim = تعديل المحاكاة
simedtdlg.lbl.Simname = :إسم المحاكاة
simedtdlg.tab.Launchcond = شروط الإطلاق
simedtdlg.tab.Simopt = خيارات المحاكاة
-simedtdlg.tab.Plotdata = عرض البيانات
+SimulationConfigDialog.tab.Plotdata = عرض البيانات
simedtdlg.tab.CustomExpressions = التعبيرات المخصصة
-simedtdlg.tab.Exportdata = تصدير البيانات
+SimulationConfigDialog.tab.Exportdata = تصدير البيانات
simedtdlg.lbl.Flightcfg = :إعدادات الطيران
simedtdlg.lbl.ttip.Flightcfg = .حدد إعدادات الرحلة لإستخدامها
simedtdlg.combo.ttip.Flightcfg = .حدد إعدادات الرحلة لإستخدامها
@@ -486,11 +486,11 @@ SimulationExtension.scripting.text.trusted.clear.ttip = إمسح حالة موث
SimulationExtension.scripting.text.trusted.cleared = .جميع البرامج النصية الآن غير موثوق بها على هذا الكمبيوتر
SimulationExtension.scripting.text.trusted.cleared.title = تم الإخلاء
-SimulationEditDialog.btn.plot = الرسم البياني
-SimulationEditDialog.btn.export = تصدير
-SimulationEditDialog.btn.edit = تعديل
-SimulationEditDialog.btn.simulate = محاكاة
-SimulationEditDialog.btn.simulateAndPlot = محاكاة وإضهار الرسم البياني
+SimulationConfigDialog.btn.plot = الرسم البياني
+SimulationConfigDialog.btn.export = تصدير
+SimulationConfigDialog.btn.edit = تعديل
+SimulationConfigDialog.btn.simulate = محاكاة
+SimulationConfigDialog.btn.simulateAndPlot = محاكاة وإضهار الرسم البياني
GeodeticComputationStrategy.flat.name = أرض مسطحة
GeodeticComputationStrategy.flat.desc = .قم بإجراء عمليات حسابية بتقريب للأرض المسطحة. كافية للرحلات على إرتفاعات منخفضة
diff --git a/core/resources/l10n/messages_cs.properties b/core/resources/l10n/messages_cs.properties
index 99a8b8c79..c80c94083 100644
--- a/core/resources/l10n/messages_cs.properties
+++ b/core/resources/l10n/messages_cs.properties
@@ -283,8 +283,8 @@ simedtdlg.title.Editsim = Uprav simulaci
simedtdlg.lbl.Simname = Jmno simulace:
simedtdlg.tab.Launchcond = Startovac podmnky
simedtdlg.tab.Simopt = Parametry simulace
-simedtdlg.tab.Plotdata = Zobraz data
-simedtdlg.tab.Exportdata = Exportuj data
+SimulationConfigDialog.tab.Plotdata = Zobraz data
+SimulationConfigDialog.tab.Exportdata = Exportuj data
simedtdlg.lbl.Motorcfg = Nastaven motoru:
simedtdlg.lbl.ttip.Motorcfg = Nastav konfiguraci motoru k pouziti.
simedtdlg.combo.ttip.motorconf = Nastav konfiguraci motoru k pouziti.
diff --git a/core/resources/l10n/messages_de.properties b/core/resources/l10n/messages_de.properties
index 033a8ff48..85a7bd0bb 100644
--- a/core/resources/l10n/messages_de.properties
+++ b/core/resources/l10n/messages_de.properties
@@ -285,9 +285,9 @@ simedtdlg.title.Editsim = Simulation bearbeiten
simedtdlg.lbl.Simname = Name der Simulation:
simedtdlg.tab.Launchcond = Startbedingungen
simedtdlg.tab.Simopt = Simulationsoptionen
-simedtdlg.tab.Plotdata = Daten plotten
+SimulationConfigDialog.tab.Plotdata = Daten plotten
simedtdlg.tab.CustomExpressions = Benutzerdefinierte Ausdrcke
-simedtdlg.tab.Exportdata = Daten exportieren
+SimulationConfigDialog.tab.Exportdata = Daten exportieren
simedtdlg.lbl.Motorcfg = Motorkonfiguration:
simedtdlg.lbl.ttip.Motorcfg = Motorkonfiguration auswhlen
simedtdlg.combo.ttip.motorconf = Die Motorkonfiguration auswhlen.
diff --git a/core/resources/l10n/messages_es.properties b/core/resources/l10n/messages_es.properties
index 313ebf684..190f0e3da 100644
--- a/core/resources/l10n/messages_es.properties
+++ b/core/resources/l10n/messages_es.properties
@@ -1012,11 +1012,11 @@ SimuRunDlg.msg.unknownerror2 = El programa puede ser inestable, Guarde todos s
! SimulationRunDialog
SimuRunDlg.title.RunSim = Ejecutar simulaciones
-SimulationEditDialog.btn.edit = Editar
-SimulationEditDialog.btn.export = Exportar
-SimulationEditDialog.btn.plot = Gr\u00e1ficos
-SimulationEditDialog.btn.simulate = Simular
-SimulationEditDialog.btn.simulateAndPlot = Simulaci\u00f3n y Gr\u00e1fico
+SimulationConfigDialog.btn.edit = Editar
+SimulationConfigDialog.btn.export = Exportar
+SimulationConfigDialog.btn.plot = Gr\u00e1ficos
+SimulationConfigDialog.btn.simulate = Simular
+SimulationConfigDialog.btn.simulateAndPlot = Simulaci\u00f3n y Gr\u00e1fico
SimulationModifierTree.OptimizationParameters = Optimizaci\u00f3n de par\u00e1metros
@@ -1787,9 +1787,9 @@ simedtdlg.lbl.ttip.Turbulenceintensity1 = La intensidad de la turbulen
simedtdlg.lbl.ttip.Turbulenceintensity2 = Valores t\u00edpicos en el campo
simedtdlg.lbl.ttip.Turbulenceintensity3 = a
simedtdlg.tab.CustomExpressions = Expresiones personalizadas
-simedtdlg.tab.Exportdata = Exportar datos
+SimulationConfigDialog.tab.Exportdata = Exportar datos
simedtdlg.tab.Launchcond = Condiciones del lanzamiento
-simedtdlg.tab.Plotdata = Datos del gr\u00e1fico
+SimulationConfigDialog.tab.Plotdata = Datos del gr\u00e1fico
simedtdlg.tab.Simopt = Opciones de simulaci\u00f3n
simedtdlg.title.Editsim = Mostrar la simulaci\u00f3n
simedtdlg.txt.longA1 = Extensiones del simulador es una caracter\u00edstica avanzada que permite que el c\u00f3digo escrito por un usuario pueda conectar e interactuar con la simulaci\u00f3n mientras \u00e9sta se est\u00e1 ejecutando.
diff --git a/core/resources/l10n/messages_fr.properties b/core/resources/l10n/messages_fr.properties
index e7ddabf40..a5a17319d 100644
--- a/core/resources/l10n/messages_fr.properties
+++ b/core/resources/l10n/messages_fr.properties
@@ -1004,11 +1004,11 @@ SimuRunDlg.msg.unknownerror2 = Le programme peut \u00EAtre instable, vous deve
! SimulationRunDialog
SimuRunDlg.title.RunSim = Simulations en cour...
-SimulationEditDialog.btn.edit = Modifier
-SimulationEditDialog.btn.export = Exporter
-SimulationEditDialog.btn.plot = Tracer
-SimulationEditDialog.btn.simulate = Simuler
-SimulationEditDialog.btn.simulateAndPlot = Simuler et tracer
+SimulationConfigDialog.btn.edit = Modifier
+SimulationConfigDialog.btn.export = Exporter
+SimulationConfigDialog.btn.plot = Tracer
+SimulationConfigDialog.btn.simulate = Simuler
+SimulationConfigDialog.btn.simulateAndPlot = Simuler et tracer
SimulationModifierTree.OptimizationParameters = Param\u00E8tres d'optimisation
@@ -1779,9 +1779,9 @@ simedtdlg.lbl.ttip.Turbulenceintensity1 = L'intensit\u00E9 de la turbu
simedtdlg.lbl.ttip.Turbulenceintensity2 = Les valeurs typiques vont de
simedtdlg.lbl.ttip.Turbulenceintensity3 = \u00E0
simedtdlg.tab.CustomExpressions = Expressions personnalis\u00E9es
-simedtdlg.tab.Exportdata = Exporter les donn\u00E9es
+SimulationConfigDialog.tab.Exportdata = Exporter les donn\u00E9es
simedtdlg.tab.Launchcond = Conditions de lancement
-simedtdlg.tab.Plotdata = Tracer les donn\u00E9es
+SimulationConfigDialog.tab.Plotdata = Tracer les donn\u00E9es
simedtdlg.tab.Simopt = Options de simulation
simedtdlg.title.Editsim = Modifier la simulation
simedtdlg.txt.longA1 = Les auditeurs de simulation sont une fonction avanc\u00E9e qui permet \u00E0 l'utilisateur d'\u00E9crire du code pour suivre et interagir avec la simulation.
diff --git a/core/resources/l10n/messages_it.properties b/core/resources/l10n/messages_it.properties
index a12bb136a..d50d6e4f5 100644
--- a/core/resources/l10n/messages_it.properties
+++ b/core/resources/l10n/messages_it.properties
@@ -287,9 +287,9 @@ simedtdlg.title.Editsim = Modifica simulazione
simedtdlg.lbl.Simname = Nome della simulazione:
simedtdlg.tab.Launchcond = Condizioni di lancio
simedtdlg.tab.Simopt = Opzioni di simulazione
-simedtdlg.tab.Plotdata = Grafico
+SimulationConfigDialog.tab.Plotdata = Grafico
simedtdlg.tab.CustomExpressions = Custom expressions
-simedtdlg.tab.Exportdata = Esporta i dati
+SimulationConfigDialog.tab.Exportdata = Esporta i dati
simedtdlg.lbl.Motorcfg = Configurazione del motore:
simedtdlg.lbl.ttip.Motorcfg = Seleziona la configurazione del motore da usare.
simedtdlg.combo.ttip.motorconf = Seleziona la configurazione del motore da usare.
diff --git a/core/resources/l10n/messages_ja.properties b/core/resources/l10n/messages_ja.properties
index f069e0746..da7f6a90f 100644
--- a/core/resources/l10n/messages_ja.properties
+++ b/core/resources/l10n/messages_ja.properties
@@ -284,9 +284,9 @@ simedtdlg.title.Editsim = \u30B7\u30DF\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u306
simedtdlg.lbl.Simname = \u30B7\u30DF\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u306E\u540D\u524D\uFF1A
simedtdlg.tab.Launchcond = \u30ED\u30FC\u30F3\u30C1\u30B3\u30F3\u30C7\u30A3\u30B7\u30E7\u30F3
simedtdlg.tab.Simopt = \u30B7\u30DF\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u30AA\u30D7\u30B7\u30E7\u30F3
-simedtdlg.tab.Plotdata = \u30C7\u30FC\u30BF\u30D7\u30ED\u30C3\u30C8
+SimulationConfigDialog.tab.Plotdata = \u30C7\u30FC\u30BF\u30D7\u30ED\u30C3\u30C8
simedtdlg.tab.CustomExpressions = \u30AB\u30B9\u30BF\u30E0\u5F0F
-simedtdlg.tab.Exportdata = \u30C7\u30FC\u30BF\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
+SimulationConfigDialog.tab.Exportdata = \u30C7\u30FC\u30BF\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
simedtdlg.lbl.Motorcfg = \u30E2\u30FC\u30BF\u30FC\u30B3\u30F3\u30D5\u30A3\u30AE\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\uFF1A
simedtdlg.lbl.ttip.Motorcfg = \u4F7F\u7528\u3059\u308B\u30E2\u30FC\u30BF\u30FC\u30B3\u30F3\u30D5\u30A3\u30AE\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u306E\u9078\u629E
simedtdlg.combo.ttip.motorconf = \u4F7F\u7528\u3059\u308B\u30E2\u30FC\u30BF\u30FC\u30B3\u30F3\u30D5\u30A3\u30AE\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u306E\u9078\u629E
diff --git a/core/resources/l10n/messages_nl.properties b/core/resources/l10n/messages_nl.properties
index 79986bd1e..b29d9c9c9 100644
--- a/core/resources/l10n/messages_nl.properties
+++ b/core/resources/l10n/messages_nl.properties
@@ -365,9 +365,9 @@ simedtdlg.title.Editsim = Bewerk simulatie
simedtdlg.lbl.Simname = Simulatienaam:
simedtdlg.tab.Launchcond = Lanceeromstandigheden
simedtdlg.tab.Simopt = Simulatie-opties
-simedtdlg.tab.Plotdata = Gegevens plotten
+SimulationConfigDialog.tab.Plotdata = Gegevens plotten
simedtdlg.tab.CustomExpressions = Aangepaste uitdrukkingen
-simedtdlg.tab.Exportdata = Exporteer data
+SimulationConfigDialog.tab.Exportdata = Exporteer data
simedtdlg.lbl.Flightcfg = Vluchtconfiguratie:
simedtdlg.lbl.ttip.Flightcfg = Selecteer de te gebruiken vluchtconfiguratie.
simedtdlg.combo.ttip.Flightcfg = Selecteer de te gebruiken vluchtconfiguratie.
@@ -464,11 +464,11 @@ SimulationExtension.scripting.text.trusted.clear.ttip = Wis de vertrouwde status
SimulationExtension.scripting.text.trusted.cleared = Alle scripts zijn nu onvertrouwd op deze computer.
SimulationExtension.scripting.text.trusted.cleared.title = Gewist
-SimulationEditDialog.btn.plot = Plot
-SimulationEditDialog.btn.export = Exporteer
-SimulationEditDialog.btn.edit = Bewerk
-SimulationEditDialog.btn.simulate = Simuleer
-SimulationEditDialog.btn.simulateAndPlot = Simuleer & Plot
+SimulationConfigDialog.btn.plot = Plot
+SimulationConfigDialog.btn.export = Exporteer
+SimulationConfigDialog.btn.edit = Bewerk
+SimulationConfigDialog.btn.simulate = Simuleer
+SimulationConfigDialog.btn.simulateAndPlot = Simuleer & Plot
GeodeticComputationStrategy.flat.name = Vlakke Aarde
GeodeticComputationStrategy.flat.desc = Voer berekeningen uit met een benadering van de vlakke aarde. Voldoende voor vluchten op lage hoogte.
diff --git a/core/resources/l10n/messages_pl.properties b/core/resources/l10n/messages_pl.properties
index 5d5a762ab..c677e482b 100644
--- a/core/resources/l10n/messages_pl.properties
+++ b/core/resources/l10n/messages_pl.properties
@@ -285,8 +285,8 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
simedtdlg.lbl.Simname = Nazwa symulacji:
simedtdlg.tab.Launchcond = Warunki startowe
simedtdlg.tab.Simopt = Opcje symulacji
- simedtdlg.tab.Plotdata = Poka\u017C wykres
- simedtdlg.tab.Exportdata = Eksportuj dane
+ SimulationConfigDialog.tab.Plotdata = Poka\u017C wykres
+ SimulationConfigDialog.tab.Exportdata = Eksportuj dane
simedtdlg.lbl.Motorcfg = Konfiguracja silnika:
simedtdlg.lbl.ttip.Motorcfg = Wybierz konfiguracj\u0119 silnika.
simedtdlg.combo.ttip.motorconf = Wybierz konfiguracj\u0119 silnika.
diff --git a/core/resources/l10n/messages_pt.properties b/core/resources/l10n/messages_pt.properties
index 4bf0268df..717e992c9 100644
--- a/core/resources/l10n/messages_pt.properties
+++ b/core/resources/l10n/messages_pt.properties
@@ -1731,9 +1731,9 @@ simedtdlg.lbl.ttip.Turbulenceintensity1 = A intensidade de turbul\u00e
simedtdlg.lbl.ttip.Turbulenceintensity2 = Os valores t\u00edpicos variam entre
simedtdlg.lbl.ttip.Turbulenceintensity3 = a
simedtdlg.tab.CustomExpressions = Express\u00f5es personalizadas
-simedtdlg.tab.Exportdata = Exportar dados
+SimulationConfigDialog.tab.Exportdata = Exportar dados
simedtdlg.tab.Launchcond = Condi\u00e7\u00f5es do lan\u00e7amento
-simedtdlg.tab.Plotdata = Plotar dados
+SimulationConfigDialog.tab.Plotdata = Plotar dados
simedtdlg.tab.Simopt = Op\u00e7\u00f5es de simula\u00e7\u00e3o
simedtdlg.title.Editsim = Editar simula\u00e7\u00e3o
simedtdlg.txt.longA1 = Observa\u00e7\u00e3o da simula\u00e7\u00e3o \u00e9 um recurso avan\u00e7ado que permite que o usu\u00e1rio escreva c\u00f3digo para observar e interagir com a simula\u00e7\u00e3o.
diff --git a/core/resources/l10n/messages_ru.properties b/core/resources/l10n/messages_ru.properties
index 2c26d7249..501905bec 100644
--- a/core/resources/l10n/messages_ru.properties
+++ b/core/resources/l10n/messages_ru.properties
@@ -374,9 +374,9 @@ simedtdlg.title.Editsim = \u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435
simedtdlg.lbl.Simname = \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
simedtdlg.tab.Launchcond = \u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0437\u0430\u043F\u0443\u0441\u043A\u0430
simedtdlg.tab.Simopt = \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-simedtdlg.tab.Plotdata = \u0413\u0440\u0430\u0444\u0438\u043A\u0438 \u0434\u0430\u043D\u043D\u044B\u0445
+SimulationConfigDialog.tab.Plotdata = \u0413\u0440\u0430\u0444\u0438\u043A\u0438 \u0434\u0430\u043D\u043D\u044B\u0445
simedtdlg.tab.CustomExpressions = \u0421\u0432\u043E\u0438 \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u044F
-simedtdlg.tab.Exportdata = \u042D\u043A\u0441\u043F\u043E\u0440\u0442 \u0434\u0430\u043D\u043D\u044B\u0445
+SimulationConfigDialog.tab.Exportdata = \u042D\u043A\u0441\u043F\u043E\u0440\u0442 \u0434\u0430\u043D\u043D\u044B\u0445
simedtdlg.lbl.Flightcfg = \u041F\u043E\u043B\u0435\u0442\u043D\u0430\u044F \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F:
simedtdlg.lbl.ttip.Flightcfg = \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u0443\u044E \u043F\u043E\u043B\u0435\u0442\u043D\u0443\u044E \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E.
simedtdlg.combo.ttip.Flightcfg = \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u0443\u044E \u043F\u043E\u043B\u0435\u0442\u043D\u0443\u044E \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E.
@@ -473,11 +473,11 @@ SimulationExtension.scripting.text.trusted.clear.ttip = \u0421\u0431\u0440\u043E
SimulationExtension.scripting.text.trusted.cleared = \u0412\u0441\u0435 \u0441\u043A\u0440\u0438\u043F\u0442\u044B \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0442\u0435\u043F\u0435\u0440\u044C \u043D\u0435 \u044F\u0432\u043B\u044F\u044E\u0442\u0441\u044F \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u043C\u0438.
SimulationExtension.scripting.text.trusted.cleared.title = \u041E\u0447\u0438\u0449\u0435\u043D\u043E
-SimulationEditDialog.btn.plot = \u0413\u0440\u0430\u0444\u0438\u043A\u0438
-SimulationEditDialog.btn.export = \u042D\u043A\u0441\u043F\u043E\u0440\u0442
-SimulationEditDialog.btn.edit = \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C
-SimulationEditDialog.btn.simulate = \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044C
-SimulationEditDialog.btn.simulateAndPlot = \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0438 \u043D\u0430\u0447\u0435\u0440\u0442\u0438\u0442\u044C
+SimulationConfigDialog.btn.plot = \u0413\u0440\u0430\u0444\u0438\u043A\u0438
+SimulationConfigDialog.btn.export = \u042D\u043A\u0441\u043F\u043E\u0440\u0442
+SimulationConfigDialog.btn.edit = \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C
+SimulationConfigDialog.btn.simulate = \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044C
+SimulationConfigDialog.btn.simulateAndPlot = \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0438 \u043D\u0430\u0447\u0435\u0440\u0442\u0438\u0442\u044C
GeodeticComputationStrategy.flat.name = \u041F\u043B\u043E\u0441\u043A\u0430\u044F \u0417\u0435\u043C\u043B\u044F
GeodeticComputationStrategy.flat.desc = \u0412\u044B\u043F\u043E\u043B\u043D\u044F\u0442\u044C \u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F \u0441 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435\u043C \u043F\u0440\u0438\u0431\u043B\u0438\u0436\u0435\u043D\u0438\u044F \u043F\u043B\u043E\u0441\u043A\u043E\u0439 \u0417\u0435\u043C\u043B\u0438. \u0422\u043E\u0447\u043D\u043E\u0441\u0442\u044C \u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D\u0430 \u0434\u043B\u044F \u043D\u0438\u0437\u043A\u0438\u0445 \u0432\u044B\u0441\u043E\u0442.
diff --git a/core/resources/l10n/messages_uk_UA.properties b/core/resources/l10n/messages_uk_UA.properties
index 72c45b44e..c5921c339 100644
--- a/core/resources/l10n/messages_uk_UA.properties
+++ b/core/resources/l10n/messages_uk_UA.properties
@@ -321,12 +321,12 @@ simedtdlg.but.savedefault = Save as default
simedtdlg.but.add = Add
simedtdlg.but.delete = Delete
simedtdlg.title.Editsim = Edit simulation
-simedtdlg.lbl.Simname = Simulation name:
+simedtdlg.lbl.Simname = Name:
simedtdlg.tab.Launchcond = Launch conditions
simedtdlg.tab.Simopt = Simulation options
-simedtdlg.tab.Plotdata = Plot data
+SimulationConfigDialog.tab.Plotdata = Plot data
simedtdlg.tab.CustomExpressions = Custom expressions
-simedtdlg.tab.Exportdata = Export data
+SimulationConfigDialog.tab.Exportdata = Export data
simedtdlg.lbl.Flightcfg = Flight configuration:
simedtdlg.lbl.ttip.Flightcfg = Select the flight configuration to use.
simedtdlg.combo.ttip.Flightcfg = Select the flight configuration to use.
@@ -396,11 +396,11 @@ simedtdlg.IntensityDesc.High = High
simedtdlg.IntensityDesc.Veryhigh = Very high
simedtdlg.IntensityDesc.Extreme = Extreme
-SimulationEditDialog.btn.plot = Plot
-SimulationEditDialog.btn.export = Export
-SimulationEditDialog.btn.edit = Edit
-SimulationEditDialog.btn.simulate = Simulate
-SimulationEditDialog.btn.simulateAndPlot = Simulate & Plot
+SimulationConfigDialog.btn.plot = Plot
+SimulationConfigDialog.btn.export = Export
+SimulationConfigDialog.btn.edit = Edit
+SimulationConfigDialog.btn.simulate = Simulate
+SimulationConfigDialog.btn.simulateAndPlot = Simulate & Plot
GeodeticComputationStrategy.flat.name = Flat Earth
GeodeticComputationStrategy.flat.desc = Perform computations with a flat Earth approximation. Sufficient for low-altitude flights.
diff --git a/core/resources/l10n/messages_zh_CN.properties b/core/resources/l10n/messages_zh_CN.properties
index 61456230c..c594ac8ce 100644
--- a/core/resources/l10n/messages_zh_CN.properties
+++ b/core/resources/l10n/messages_zh_CN.properties
@@ -1062,11 +1062,11 @@ SimuRunDlg.msg.errorOccurred = \u4EFF\u771F\u65F6\u51FA\u73B0\u9519\u8BEF:
! SimulationRunDialog
SimuRunDlg.title.RunSim = \u8FD0\u884C\u4EFF\u771F...
-SimulationEditDialog.btn.edit = \u7F16\u8F91
-SimulationEditDialog.btn.export = \u5BFC\u51FA
-SimulationEditDialog.btn.plot = \u6570\u636E\u56FE
-SimulationEditDialog.btn.simulate = \u4EFF\u771F
-SimulationEditDialog.btn.simulateAndPlot = \u4EFF\u771F & \u6570\u636E\u56FE
+SimulationConfigDialog.btn.edit = \u7F16\u8F91
+SimulationConfigDialog.btn.export = \u5BFC\u51FA
+SimulationConfigDialog.btn.plot = \u6570\u636E\u56FE
+SimulationConfigDialog.btn.simulate = \u4EFF\u771F
+SimulationConfigDialog.btn.simulateAndPlot = \u4EFF\u771F & \u6570\u636E\u56FE
SimulationExtension.javacode.className = \u5B8C\u6574\u7684Java\u7C7B\u540D:
SimulationExtension.javacode.desc = \u6DFB\u52A0\u81EA\u5B9A\u4E49SimulationListener(\u76D1\u542C\u4E8B\u4EF6)
@@ -1877,9 +1877,9 @@ simedtdlg.lbl.ttip.Turbulenceintensity2 = \u5178\u578B\u53D6\u503C\u8303\u56
simedtdlg.lbl.ttip.Turbulenceintensity3 = \u5230
simedtdlg.lbl.ttip.Winddirection = \u98CE\u5411, 0-360\u5EA6.
0 \u662F\u5317\u98CE,
90 \u662F\u4E1C\u98CE
simedtdlg.tab.CustomExpressions = \u81EA\u5B9A\u4E49\u8868\u8FBE\u5F0F
-simedtdlg.tab.Exportdata = \u8F93\u51FA\u6570\u636E
+SimulationConfigDialog.tab.Exportdata = \u8F93\u51FA\u6570\u636E
simedtdlg.tab.Launchcond = \u53D1\u5C04\u6761\u4EF6
-simedtdlg.tab.Plotdata = \u6570\u636E\u7ED8\u56FE
+SimulationConfigDialog.tab.Plotdata = \u6570\u636E\u7ED8\u56FE
simedtdlg.tab.Simopt = \u6A21\u62DF\u9009\u9879
simedtdlg.title.Editsim = \u7F16\u8F91\u4EFF\u771F
simedtdlg.txt.longA1 = \u4EFF\u771F\u76D1\u542C\u5668(Simulation Listener)\u662F\u4E00\u4E2A\u9AD8\u7EA7\u7279\u6027,\u5141\u8BB8\u7528\u6237\u81EA\u5B9A\u4E49\u4EE3\u7801\u4E0E\u4EFF\u771F\u8FC7\u7A0B\u4EA4\u4E92
diff --git a/core/resources/pix/icons/refresh_sim.png b/core/resources/pix/icons/refresh_sim.png
new file mode 100644
index 000000000..66c8e8c48
Binary files /dev/null and b/core/resources/pix/icons/refresh_sim.png differ
diff --git a/core/resources/pix/icons/sim_cantrun.png b/core/resources/pix/icons/sim_cantrun.png
new file mode 100644
index 000000000..0cfd58596
Binary files /dev/null and b/core/resources/pix/icons/sim_cantrun.png differ
diff --git a/core/resources/pix/icons/tick.png b/core/resources/pix/icons/tick.png
new file mode 100644
index 000000000..a9925a06a
Binary files /dev/null and b/core/resources/pix/icons/tick.png differ
diff --git a/core/resources/pix/icons/warning_high.png b/core/resources/pix/icons/warning_high.png
new file mode 100644
index 000000000..c37bd062e
Binary files /dev/null and b/core/resources/pix/icons/warning_high.png differ
diff --git a/core/resources/pix/icons/warning_low.png b/core/resources/pix/icons/warning_low.png
new file mode 100644
index 000000000..12cd1aef9
Binary files /dev/null and b/core/resources/pix/icons/warning_low.png differ
diff --git a/core/resources/pix/icons/warning_normal.png b/core/resources/pix/icons/warning_normal.png
new file mode 100644
index 000000000..628cf2dae
Binary files /dev/null and b/core/resources/pix/icons/warning_normal.png differ
diff --git a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java
index cdb3f499f..e3bf4b8bc 100644
--- a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java
+++ b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java
@@ -216,23 +216,8 @@ public class OpenRocketSaver extends RocketSaver {
private int calculateNecessaryFileVersion(OpenRocketDocument document, StorageOptions opts) {
/*
* NOTE: Remember to update the supported versions in DocumentConfig as well!
- *
- * File version 1.9 is required for:
- * - new-style positioning
- * - external/parallel booster stages
- * - external pods
- * - Rail Buttons
- * - Flight event source saving
- *
- * Otherwise use version 1.9.
*/
-
- /////////////////
- // Version 1.9 //
- /////////////////
- // for any new-style positioning: 'axialoffset', 'angleoffset', 'radiusoffset' tags
- // these tags are used for any RocketComponent child classes positioning... so... ALL the classes.
- return FILE_VERSION_DIVISOR + 9;
+ return FILE_VERSION_DIVISOR + 10;
}
@@ -409,7 +394,7 @@ public class OpenRocketSaver extends RocketSaver {
indent++;
for (Warning w : data.getWarningSet()) {
- writeElement("warning", TextUtil.escapeXML(w.toString()));
+ writeElementWithAttribute("warning", "priority", w.getPriority().getExportLabel(), TextUtil.escapeXML(w.toString()));
}
// Check whether to store data
@@ -606,6 +591,12 @@ public class OpenRocketSaver extends RocketSaver {
content = "";
writeln("<" + element + ">" + TextUtil.escapeXML(content) + "" + element + ">");
}
+
+ private void writeElementWithAttribute(String element, String attributeName, String attribute, Object content) throws IOException {
+ content = content == null ? "" : content;
+
+ writeln("<" + element + " " + attributeName + " = \"" + attribute + "\">" + TextUtil.escapeXML(content) + "" + element + ">");
+ }
diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java
index 489fec875..781461e01 100644
--- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java
+++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java
@@ -52,7 +52,7 @@ import net.sf.openrocket.util.Reflection;
class DocumentConfig {
/* Remember to update OpenRocketSaver as well! */
- public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9" };
+ public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10" };
/**
* Divisor used in converting an integer version to the point-represented version.
diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/FlightDataHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/FlightDataHandler.java
index d23537401..369e0d235 100644
--- a/core/src/net/sf/openrocket/file/openrocket/importt/FlightDataHandler.java
+++ b/core/src/net/sf/openrocket/file/openrocket/importt/FlightDataHandler.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import net.sf.openrocket.logging.MessagePriority;
import net.sf.openrocket.logging.Warning;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.file.DocumentLoadingContext;
@@ -83,7 +84,9 @@ class FlightDataHandler extends AbstractElementHandler {
branches.add(branch);
}
} else if (element.equals("warning")) {
- warningSet.add(Warning.fromString(content));
+ String priorityStr = attributes.get("priority");
+ MessagePriority priority = MessagePriority.fromExportLabel(priorityStr);
+ warningSet.add(Warning.fromString(content, priority));
}
}
diff --git a/core/src/net/sf/openrocket/logging/Message.java b/core/src/net/sf/openrocket/logging/Message.java
index e0b6ba3eb..2216b0f4d 100644
--- a/core/src/net/sf/openrocket/logging/Message.java
+++ b/core/src/net/sf/openrocket/logging/Message.java
@@ -10,12 +10,7 @@ public abstract class Message implements Cloneable {
/** The rocket component(s) that are the source of this message **/
private RocketComponent[] sources = null;
- /**
- * @return a Message with the specific text.
- */
- public static Message fromString(String text) {
- return new Warning.Other(text);
- }
+ private MessagePriority priority = MessagePriority.NORMAL;
/**
* Returns the message text + message source objects.
@@ -75,6 +70,21 @@ public abstract class Message implements Cloneable {
this.sources = sources;
}
+ /**
+ * Return the priority of this message.
+ * @return the priority of this message.
+ */
+ public MessagePriority getPriority() {
+ return priority;
+ }
+
+ /**
+ * Set the priority of this message.
+ * @param priority the priority of this message.
+ */
+ public void setPriority(MessagePriority priority) {
+ this.priority = priority;
+ }
/**
* Two Messages are by default considered equal if they are of
@@ -84,7 +94,8 @@ public abstract class Message implements Cloneable {
*/
@Override
public boolean equals(Object o) {
- return o != null && (o.getClass() == this.getClass() && sourcesEqual(((Message) o).sources, sources));
+ return o != null && (o.getClass() == this.getClass() && sourcesEqual(((Message) o).sources, sources))
+ && ((Message) o).priority == priority;
}
/**
@@ -109,6 +120,7 @@ public abstract class Message implements Cloneable {
protected Object clone() throws CloneNotSupportedException {
Message clone = (Message) super.clone();
clone.sources = this.sources;
+ clone.priority = this.priority;
return clone;
}
}
diff --git a/core/src/net/sf/openrocket/logging/MessagePriority.java b/core/src/net/sf/openrocket/logging/MessagePriority.java
new file mode 100644
index 000000000..885f6bcea
--- /dev/null
+++ b/core/src/net/sf/openrocket/logging/MessagePriority.java
@@ -0,0 +1,29 @@
+package net.sf.openrocket.logging;
+
+/**
+ * The priority of a message.
+ */
+public enum MessagePriority {
+ LOW("LOW"),
+ NORMAL("NORMAL"),
+ HIGH("HIGH");
+
+ private String exportLabel;
+
+ MessagePriority(String exportLabel) {
+ this.exportLabel = exportLabel;
+ }
+
+ public String getExportLabel() {
+ return exportLabel;
+ }
+
+ public static MessagePriority fromExportLabel(String exportLabel) {
+ for (MessagePriority priority : MessagePriority.values()) {
+ if (priority.exportLabel.equals(exportLabel)) {
+ return priority;
+ }
+ }
+ return NORMAL;
+ }
+}
diff --git a/core/src/net/sf/openrocket/logging/MessageSet.java b/core/src/net/sf/openrocket/logging/MessageSet.java
index adf490edb..805d4108d 100644
--- a/core/src/net/sf/openrocket/logging/MessageSet.java
+++ b/core/src/net/sf/openrocket/logging/MessageSet.java
@@ -8,6 +8,7 @@ import net.sf.openrocket.util.Mutable;
import java.util.AbstractSet;
import java.util.Iterator;
+import java.util.List;
/**
* A set that contains multiple Messages. When adding a
@@ -116,6 +117,36 @@ public abstract class MessageSet extends AbstractSet imple
return messages.size();
}
+ /**
+ * Returns the number of messages with the specified priority.
+ * @param priority the priority
+ * @return the number of messages with the specified priority.
+ */
+ public int getNrOfMessagesWithPriority(MessagePriority priority) {
+ int count = 0;
+ for (E m : messages) {
+ if (m.getPriority() == priority) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Returns a list of messages with the specified priority.
+ *
+ * @param priority the priority of the messages to retrieve
+ * @return a list of messages with the specified priority
+ */
+ public List getMessagesWithPriority(MessagePriority priority) {
+ List list = new ArrayList<>();
+ for (E m : messages) {
+ if (m.getPriority() == priority) {
+ list.add(m);
+ }
+ }
+ return list;
+ }
public void immute() {
mutable.immute();
diff --git a/core/src/net/sf/openrocket/logging/Warning.java b/core/src/net/sf/openrocket/logging/Warning.java
index 0f085fb8d..08211acf9 100644
--- a/core/src/net/sf/openrocket/logging/Warning.java
+++ b/core/src/net/sf/openrocket/logging/Warning.java
@@ -2,7 +2,6 @@ package net.sf.openrocket.logging;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.simulation.FlightEvent;
import net.sf.openrocket.unit.UnitGroup;
@@ -16,10 +15,17 @@ public abstract class Warning extends Message {
private static final Translator trans = Application.getTranslator();
/**
- * @return a Warning with the specific text.
+ * @return a Message with the specific text and priority.
+ */
+ public static Warning fromString(String text, MessagePriority priority) {
+ return new Warning.Other(text, priority);
+ }
+
+ /**
+ * @return a Message with the specific text.
*/
public static Warning fromString(String text) {
- return new Warning.Other(text);
+ return fromString(text, MessagePriority.NORMAL);
}
@@ -42,6 +48,7 @@ public abstract class Warning extends Message {
*/
public LargeAOA(double aoa) {
this.aoa = aoa;
+ setPriority(MessagePriority.NORMAL);
}
@Override
@@ -65,10 +72,11 @@ public abstract class Warning extends Message {
return (o.aoa > this.aoa);
}
- @Override
+ // Don't compare aoa, otherwise you have a million LargeAOA warnings with different values
+ /*@Override
public boolean equals(Object o) {
return super.equals(o) && Double.compare(((LargeAOA) o).aoa, aoa) == 0;
- }
+ }*/
@Override
protected Object clone() throws CloneNotSupportedException {
@@ -93,6 +101,7 @@ public abstract class Warning extends Message {
*/
public HighSpeedDeployment(double speed) {
this.recoverySpeed = speed;
+ setPriority(MessagePriority.NORMAL);
}
@Override
@@ -108,10 +117,11 @@ public abstract class Warning extends Message {
return false;
}
- @Override
+ // Don't compare recoverySpeed, otherwise you have a million HighSpeedDeployment warnings with different values
+ /*@Override
public boolean equals(Object o) {
return super.equals(o) && Double.compare(((HighSpeedDeployment) o).recoverySpeed, recoverySpeed) == 0;
- }
+ }*/
@Override
protected Object clone() throws CloneNotSupportedException {
@@ -135,6 +145,7 @@ public abstract class Warning extends Message {
*/
public EventAfterLanding(FlightEvent _event) {
this.event = _event;
+ setPriority(MessagePriority.HIGH);
}
// I want a warning on every event that occurs after we land,
@@ -172,7 +183,11 @@ public abstract class Warning extends Message {
private double diameter = Double.NaN;
private double length = Double.NaN;
private double delay = Double.NaN;
-
+
+ public MissingMotor() {
+ setPriority(MessagePriority.HIGH);
+ }
+
@Override
public String getMessageDescription() {
String str = "No motor with designation '" + designation + "'";
@@ -345,8 +360,13 @@ public abstract class Warning extends Message {
public static class Other extends Warning {
private String description;
- public Other(String description) {
+ public Other(String description, MessagePriority priority) {
this.description = description;
+ setPriority(priority);
+ }
+
+ public Other(String description) {
+ this(description, MessagePriority.NORMAL);
}
@Override
@@ -379,68 +399,75 @@ public abstract class Warning extends Message {
/** A Warning that the body diameter is discontinuous. */
- ////Discontinuity in rocket body diameter.
- public static final Warning DIAMETER_DISCONTINUITY = new Other(trans.get("Warning.DISCONTINUITY"));
+ public static final Warning DIAMETER_DISCONTINUITY = new Other(trans.get("Warning.DISCONTINUITY"), MessagePriority.NORMAL);
/** A Warning that a ComponentAssembly has an open forward end */
- public static final Warning OPEN_AIRFRAME_FORWARD = new Other(trans.get("Warning.OPEN_AIRFRAME_FORWARD"));
+ public static final Warning OPEN_AIRFRAME_FORWARD = new Other(trans.get("Warning.OPEN_AIRFRAME_FORWARD"), MessagePriority.NORMAL);
/** A Warning that there is a gap in the airframe */
- public static final Warning AIRFRAME_GAP = new Other(trans.get("Warning.AIRFRAME_GAP"));
+ public static final Warning AIRFRAME_GAP = new Other(trans.get("Warning.AIRFRAME_GAP"), MessagePriority.NORMAL);
/** A Warning that there are overlapping airframe components */
- public static final Warning AIRFRAME_OVERLAP = new Other(trans.get("Warning.AIRFRAME_OVERLAP"));
+ public static final Warning AIRFRAME_OVERLAP = new Other(trans.get("Warning.AIRFRAME_OVERLAP"), MessagePriority.NORMAL);
/** A Warning that an inline podset is completely forward of its parent component */
- public static final Warning PODSET_FORWARD = new Other(trans.get("Warning.PODSET_FORWARD"));
+ public static final Warning PODSET_FORWARD = new Other(trans.get("Warning.PODSET_FORWARD"), MessagePriority.NORMAL);
/** A Warning that an inline podset overlaps its parent component */
- public static final Warning PODSET_OVERLAP = new Other(trans.get("Warning.PODSET_OVERLAP"));
+ public static final Warning PODSET_OVERLAP = new Other(trans.get("Warning.PODSET_OVERLAP"), MessagePriority.NORMAL);
/** A Warning that the fins are thick compared to the rocket body. */
////Thick fins may not be modeled accurately.
- public static final Warning THICK_FIN = new Other(trans.get("Warning.THICK_FIN"));
+ public static final Warning THICK_FIN = new Other(trans.get("Warning.THICK_FIN"), MessagePriority.NORMAL);
/** A Warning that the fins have jagged edges. */
- ////Jagged-edged fin predictions may be inaccurate.
- public static final Warning JAGGED_EDGED_FIN = new Other(trans.get("Warning.JAGGED_EDGED_FIN"));
+ public static final Warning JAGGED_EDGED_FIN = new Other(trans.get("Warning.JAGGED_EDGED_FIN"), MessagePriority.NORMAL);
/** A Warning that the fins have a zero area. */
- ////Fins with no area will not affect aerodynamics
- public static final Warning ZERO_AREA_FIN = new Other(trans.get("Warning.ZERO_AREA_FIN"));
+ public static final Warning ZERO_AREA_FIN = new Other(trans.get("Warning.ZERO_AREA_FIN"), MessagePriority.NORMAL);
/** A Warning that simulation listeners have affected the simulation */
- ////Listeners modified the flight simulation
- public static final Warning LISTENERS_AFFECTED = new Other(trans.get("Warning.LISTENERS_AFFECTED"));
+ public static final Warning LISTENERS_AFFECTED = new Other(trans.get("Warning.LISTENERS_AFFECTED"), MessagePriority.LOW);
- ////No recovery device for simulation
- public static final Warning NO_RECOVERY_DEVICE = new Other(trans.get("Warning.NO_RECOVERY_DEVICE"));
+ /** No recovery device defined in the simulation. */
+ public static final Warning NO_RECOVERY_DEVICE = new Other(trans.get("Warning.NO_RECOVERY_DEVICE"), MessagePriority.HIGH);
- //// Invalid parameter encountered, ignoring.
- public static final Warning FILE_INVALID_PARAMETER = new Other(trans.get("Warning.FILE_INVALID_PARAMETER"));
-
- public static final Warning PARALLEL_FINS = new Other(trans.get("Warning.PARALLEL_FINS"));
+ /** Invalid parameter encountered, ignoring. */
+ public static final Warning FILE_INVALID_PARAMETER = new Other(trans.get("Warning.FILE_INVALID_PARAMETER"), MessagePriority.NORMAL);
- public static final Warning SUPERSONIC = new Other(trans.get("Warning.SUPERSONIC"));
-
- public static final Warning RECOVERY_LAUNCH_ROD = new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD"));
-
- public static final Warning TUMBLE_UNDER_THRUST = new Other(trans.get("Warning.TUMBLE_UNDER_THRUST"));
+ /** Too many parallel fins */
+ public static final Warning PARALLEL_FINS = new Other(trans.get("Warning.PARALLEL_FINS"), MessagePriority.NORMAL);
- public static final Warning EVENT_AFTER_LANDING = new Other(trans.get("Warning.EVENT_AFTER_LANDING"));
+ /** Body calculations may not be entirely accurate at supersonic speeds. */
+ public static final Warning SUPERSONIC = new Other(trans.get("Warning.SUPERSONIC"), MessagePriority.NORMAL);
- public static final Warning ZERO_VOLUME_BODY = new Other(trans.get("Warning.ZERO_VOLUME_BODY"));
+ /** Recovery device deployed while on the launch guide. */
+ public static final Warning RECOVERY_LAUNCH_ROD = new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD"), MessagePriority.HIGH);
- public static final Warning TUBE_SEPARATION = new Other(trans.get("Warning.TUBE_SEPARATION"));
- public static final Warning TUBE_OVERLAP = new Other(trans.get("Warning.TUBE_OVERLAP"));
+ /** Stage began to tumble under thrust. */
+ public static final Warning TUMBLE_UNDER_THRUST = new Other(trans.get("Warning.TUMBLE_UNDER_THRUST"), MessagePriority.HIGH);
- public static final Warning OBJ_ZERO_THICKNESS = new Other(trans.get("Warning.OBJ_ZERO_THICKNESS"));
+ /** Flight Event occurred after landing: */
+ public static final Warning EVENT_AFTER_LANDING = new Other(trans.get("Warning.EVENT_AFTER_LANDING"), MessagePriority.NORMAL);
+
+ /** Zero-volume bodies may not simulate accurately */
+ public static final Warning ZERO_VOLUME_BODY = new Other(trans.get("Warning.ZERO_VOLUME_BODY"), MessagePriority.NORMAL);
+
+ /** Space between tube fins may not simulate accurately. */
+ public static final Warning TUBE_SEPARATION = new Other(trans.get("Warning.TUBE_SEPARATION"), MessagePriority.NORMAL);
+
+ /** Overlapping tube fins may not simulate accurately. */
+ public static final Warning TUBE_OVERLAP = new Other(trans.get("Warning.TUBE_OVERLAP"), MessagePriority.NORMAL);
+
+ /** Zero-thickness component can cause issues for 3D printing */
+ public static final Warning OBJ_ZERO_THICKNESS = new Other(trans.get("Warning.OBJ_ZERO_THICKNESS"), MessagePriority.NORMAL);
/** A Warning that stage separation occurred at other than the last stage */
- 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"), MessagePriority.NORMAL);
/** A Warning that stage separation occurred before the rocket cleared the launch rod or rail */
- public static final Warning EARLY_SEPARATION = new Other(trans.get("Warning.EARLY_SEPARATION"));
+ public static final Warning EARLY_SEPARATION = new Other(trans.get("Warning.EARLY_SEPARATION"), MessagePriority.HIGH);
- public static final Warning EMPTY_BRANCH = new Other(trans.get("Warning.EMPTY_BRANCH"));
+ /** Simulation branch contains no data */
+ public static final Warning EMPTY_BRANCH = new Other(trans.get("Warning.EMPTY_BRANCH"), MessagePriority.HIGH);
}
diff --git a/core/src/net/sf/openrocket/logging/WarningSet.java b/core/src/net/sf/openrocket/logging/WarningSet.java
index d93a20d0e..98a80cc93 100644
--- a/core/src/net/sf/openrocket/logging/WarningSet.java
+++ b/core/src/net/sf/openrocket/logging/WarningSet.java
@@ -2,6 +2,9 @@ package net.sf.openrocket.logging;
import net.sf.openrocket.util.BugException;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* A set that contains multiple Warnings. When adding a
* {@link Warning} to this set, the contents is checked for a warning of the
@@ -27,6 +30,41 @@ public class WarningSet extends MessageSet {
return add(Warning.fromString(s));
}
+ public int getNrOfCriticalWarnings() {
+ return getNrOfMessagesWithPriority(MessagePriority.HIGH);
+ }
+
+ public int getNrOfNormalWarnings() {
+ return getNrOfMessagesWithPriority(MessagePriority.NORMAL);
+ }
+
+ public int getNrOfInformativeWarnings() {
+ return getNrOfMessagesWithPriority(MessagePriority.LOW);
+ }
+
+ public List getCriticalWarnings() {
+ List list = getMessagesWithPriority(MessagePriority.HIGH);
+ return convertMessageListToWarningList(list);
+ }
+
+ public List getNormalWarnings() {
+ List list = getMessagesWithPriority(MessagePriority.NORMAL);
+ return convertMessageListToWarningList(list);
+ }
+
+ public List getInformativeWarnings() {
+ List list = getMessagesWithPriority(MessagePriority.LOW);
+ return convertMessageListToWarningList(list);
+ }
+
+ private static List convertMessageListToWarningList(List list) {
+ List warnings = new ArrayList<>(list.size());
+ for (Message m : list) {
+ warnings.add((Warning) m);
+ }
+ return warnings;
+ }
+
@Override
public WarningSet clone() {
try {
diff --git a/core/src/net/sf/openrocket/util/TestRockets.java b/core/src/net/sf/openrocket/util/TestRockets.java
index 500bacaa7..65399c652 100644
--- a/core/src/net/sf/openrocket/util/TestRockets.java
+++ b/core/src/net/sf/openrocket/util/TestRockets.java
@@ -1789,7 +1789,7 @@ public class TestRockets {
}
- public static OpenRocketDocument makeTestRocket_v107_withSimulationExtension(String script) {
+ public static OpenRocketDocument makeTestRocket_v110_withSimulationExtension(String script) {
Rocket rocket = makeEstesAlphaIII();
OpenRocketDocument document = OpenRocketDocumentFactory.createDocumentFromRocket(rocket);
Simulation sim = new Simulation(rocket);
diff --git a/core/test/net/sf/openrocket/file/openrocket/OpenRocketSaverTest.java b/core/test/net/sf/openrocket/file/openrocket/OpenRocketSaverTest.java
index e24200ad0..d96a0e912 100644
--- a/core/test/net/sf/openrocket/file/openrocket/OpenRocketSaverTest.java
+++ b/core/test/net/sf/openrocket/file/openrocket/OpenRocketSaverTest.java
@@ -133,7 +133,7 @@ public class OpenRocketSaverTest {
rocketDocs.add(TestRockets.makeTestRocket_v106_withMotorMountIgnitionConfig());
rocketDocs.add(TestRockets.makeTestRocket_v106_withRecoveryDeviceDeploymentConfig());
rocketDocs.add(TestRockets.makeTestRocket_v106_withStageSeparationConfig());
- rocketDocs.add(TestRockets.makeTestRocket_v107_withSimulationExtension(SIMULATION_EXTENSION_SCRIPT));
+ rocketDocs.add(TestRockets.makeTestRocket_v110_withSimulationExtension(SIMULATION_EXTENSION_SCRIPT));
rocketDocs.add(TestRockets.makeTestRocket_v108_withBoosters());
rocketDocs.add(TestRockets.makeTestRocket_v108_withDisabledStage());
rocketDocs.add(TestRockets.makeTestRocket_for_estimateFileSize());
@@ -222,7 +222,7 @@ public class OpenRocketSaverTest {
@Test
public void testUntrustedScriptDisabledOnLoad() {
- OpenRocketDocument rocketDoc = TestRockets.makeTestRocket_v107_withSimulationExtension(SIMULATION_EXTENSION_SCRIPT);
+ OpenRocketDocument rocketDoc = TestRockets.makeTestRocket_v110_withSimulationExtension(SIMULATION_EXTENSION_SCRIPT);
StorageOptions options = new StorageOptions();
File file = saveRocket(rocketDoc, options);
OpenRocketDocument rocketDocLoaded = loadRocket(file.getPath());
@@ -236,7 +236,7 @@ public class OpenRocketSaverTest {
@Test
public void testTrustedScriptEnabledOnLoad() {
- OpenRocketDocument rocketDoc = TestRockets.makeTestRocket_v107_withSimulationExtension("TESTING");
+ OpenRocketDocument rocketDoc = TestRockets.makeTestRocket_v110_withSimulationExtension("TESTING");
injector.getInstance(ScriptingUtil.class).setTrustedScript("JavaScript", "TESTING", true);
StorageOptions options = new StorageOptions();
File file = saveRocket(rocketDoc, options);
@@ -326,13 +326,13 @@ public class OpenRocketSaverTest {
}
////////////////////////////////
- // Tests for File Version 1.7 //
+ // Tests for File Version 1.10 //
////////////////////////////////
@Test
- public void testFileVersion109_withSimulationExtension() {
- OpenRocketDocument rocketDoc = TestRockets.makeTestRocket_v107_withSimulationExtension(SIMULATION_EXTENSION_SCRIPT);
- assertEquals(109, getCalculatedFileVersion(rocketDoc));
+ public void testFileVersion110_withSimulationExtension() {
+ OpenRocketDocument rocketDoc = TestRockets.makeTestRocket_v110_withSimulationExtension(SIMULATION_EXTENSION_SCRIPT);
+ assertEquals(110, getCalculatedFileVersion(rocketDoc));
}
diff --git a/fileformat.txt b/fileformat.txt
index aa3093182..ae33ec0b5 100644
--- a/fileformat.txt
+++ b/fileformat.txt
@@ -64,5 +64,8 @@ The following file format versions exist:
Rename to ( remains for backward compatibility)
Rename to ( remains for backward compatibility)
-1.9: Introduced with OpenRocket 23.xx.
- Added ID for each rocket component, to in turn add this ID as a source for flight events.
\ No newline at end of file
+1.9: Introduced with OpenRocket 23.09.
+ Added ID for each rocket component, to in turn add this ID as a source for flight events.
+
+1.10: Introduced with OpenRocket 24.XX.
+ Added a priority attribute to simulation warnings.
diff --git a/swing/src/net/sf/openrocket/file/wavefrontobj/OBJOptionChooser.java b/swing/src/net/sf/openrocket/file/wavefrontobj/OBJOptionChooser.java
index 84e4ed174..8bade715a 100644
--- a/swing/src/net/sf/openrocket/file/wavefrontobj/OBJOptionChooser.java
+++ b/swing/src/net/sf/openrocket/file/wavefrontobj/OBJOptionChooser.java
@@ -71,7 +71,7 @@ public class OBJOptionChooser extends JPanel {
private int totallyNormalCounter = 0;
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
static {
initColors();
@@ -339,7 +339,7 @@ public class OBJOptionChooser extends JPanel {
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
}
/**
@@ -348,7 +348,7 @@ public class OBJOptionChooser extends JPanel {
* @param loserButton The button to un-highlight
*/
private void highlightButton(JButton highlightButton, JButton loserButton) {
- highlightButton.setBorder(BorderFactory.createLineBorder(darkWarningColor));
+ highlightButton.setBorder(BorderFactory.createLineBorder(darkErrorColor));
loserButton.setBorder(UIManager.getBorder("Button.border"));
}
diff --git a/swing/src/net/sf/openrocket/gui/components/StyledLabel.java b/swing/src/net/sf/openrocket/gui/components/StyledLabel.java
index bf2a29314..60bda798c 100644
--- a/swing/src/net/sf/openrocket/gui/components/StyledLabel.java
+++ b/swing/src/net/sf/openrocket/gui/components/StyledLabel.java
@@ -1,8 +1,11 @@
package net.sf.openrocket.gui.components;
+import net.sf.openrocket.gui.util.Icons;
+
import java.awt.Color;
import java.awt.Font;
+import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
@@ -57,6 +60,10 @@ public class StyledLabel extends JLabel {
resizeFont(size);
checkPreferredSize(size, Style.PLAIN);
}
+
+ public StyledLabel(Icon icon, float size) {
+ super(Icons.getScaledIcon(icon, size));
+ }
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
index 4e7fb85c5..e79687320 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
@@ -99,7 +99,7 @@ public class RocketComponentConfig extends JPanel implements Invalidatable, Inva
private boolean allSameType; // Checks whether all listener components are of the same type as
private boolean allMassive; // Checks whether all listener components, and this component, are massive
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
private static Color multiCompEditColor;
private static Border border;
@@ -205,7 +205,7 @@ public class RocketComponentConfig extends JPanel implements Invalidatable, Inva
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
multiCompEditColor = GUIUtil.getUITheme().getMultiCompEditColor();
border = GUIUtil.getUITheme().getBorder();
}
@@ -539,7 +539,7 @@ public class RocketComponentConfig extends JPanel implements Invalidatable, Inva
StyledLabel labelMassOverriddenBy = new StyledLabel(
String.format(trans.get("RocketCompCfg.lbl.MassOverriddenBy"), component.getMassOverriddenBy().getName()),
0, StyledLabel.Style.BOLD);
- labelMassOverriddenBy.setFontColor(darkWarningColor);
+ labelMassOverriddenBy.setFontColor(darkErrorColor);
labelMassOverriddenBy.setToolTipText(
String.format(trans.get("RocketCompCfg.lbl.MassOverriddenBy.ttip"), component.getMassOverriddenBy().getName()));
checkboxes.add(labelMassOverriddenBy, "gapleft 25lp, wrap");
@@ -605,7 +605,7 @@ public class RocketComponentConfig extends JPanel implements Invalidatable, Inva
StyledLabel labelCGOverriddenBy = new StyledLabel(
String.format(trans.get("RocketCompCfg.lbl.CGOverriddenBy"), component.getCGOverriddenBy().getName()),
0, StyledLabel.Style.BOLD);
- labelCGOverriddenBy.setFontColor(darkWarningColor);
+ labelCGOverriddenBy.setFontColor(darkErrorColor);
labelCGOverriddenBy.setToolTipText(
String.format(trans.get("RocketCompCfg.lbl.CGOverriddenBy.ttip"), component.getCGOverriddenBy().getName()));
checkboxes.add(labelCGOverriddenBy, "gapleft 25lp, wrap");
@@ -702,7 +702,7 @@ public class RocketComponentConfig extends JPanel implements Invalidatable, Inva
StyledLabel labelCDOverriddenBy = new StyledLabel(
String.format(trans.get("RocketCompCfg.lbl.CDOverriddenBy"), component.getCDOverriddenBy().getName()),
0, StyledLabel.Style.BOLD);
- labelCDOverriddenBy.setFontColor(darkWarningColor);
+ labelCDOverriddenBy.setFontColor(darkErrorColor);
labelCDOverriddenBy.setToolTipText(
String.format(trans.get("RocketCompCfg.lbl.CDOverriddenBy"), component.getCDOverriddenBy().getName()));
checkboxes.add(labelCDOverriddenBy, "gapleft 25lp, wrap");
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java
index 7e9818629..2f6e3c4f6 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/BugReportDialog.java
@@ -49,7 +49,7 @@ public class BugReportDialog extends JDialog {
private static final Translator trans = Application.getTranslator();
private static final SwingPreferences preferences = (SwingPreferences) Application.getPreferences();
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
static {
initColors();
@@ -117,7 +117,7 @@ public class BugReportDialog extends JDialog {
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
}
/**
@@ -194,7 +194,7 @@ public class BugReportDialog extends JDialog {
private static void addBugReportInformation(StringBuilder sb) {
sb.append("---------- Bug report ----------\n");
sb.append('\n');
- Color color = darkWarningColor;
+ Color color = darkErrorColor;
sb.append(String.format("Please include a description about what actions you were " +
"performing when the exception occurred:\n", color.getRed(), color.getGreen(), color.getBlue()));
sb.append("(You can edit text directly in this window)\n");
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/ErrorWarningDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/ErrorWarningDialog.java
index 13e2a8b1f..6a4979b00 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/ErrorWarningDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/ErrorWarningDialog.java
@@ -29,7 +29,7 @@ import java.awt.event.MouseEvent;
@SuppressWarnings("serial")
public abstract class ErrorWarningDialog {
private static Border border;
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
private static Color textSelectionForegroundColor;
static {
@@ -43,7 +43,7 @@ public abstract class ErrorWarningDialog {
private static void updateColors() {
border = GUIUtil.getUITheme().getBorder();
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
textSelectionForegroundColor = GUIUtil.getUITheme().getTextSelectionForegroundColor();
}
@@ -51,13 +51,13 @@ public abstract class ErrorWarningDialog {
JPanel content = new JPanel(new MigLayout("ins 0, fillx"));
StyledLabel label = new StyledLabel("Errors");
- label.setFontColor(darkWarningColor);
+ label.setFontColor(darkErrorColor);
content.add(label, "wrap, gaptop 15lp");
Error[] e = errors.toArray(new Error[0]);
final JList errorList = new JList<>(e);
errorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- errorList.setCellRenderer(new ErrorListCellRenderer());
+ errorList.setCellRenderer(new BetterListCellRenderer(darkErrorColor));
JScrollPane errorPane = new JScrollPane(errorList);
errorList.setBorder(border);
content.add(errorPane, "wrap, growx");
@@ -99,21 +99,4 @@ public abstract class ErrorWarningDialog {
title, JOptionPane.WARNING_MESSAGE);
}
-
- private static class ErrorListCellRenderer extends BetterListCellRenderer {
- @Override
- public Component getListCellRendererComponent(JList> list, Object value, int index,
- boolean isSelected, boolean cellHasFocus) {
- JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-
- // Text color
- if (isSelected) {
- label.setForeground(textSelectionForegroundColor);
- } else {
- label.setForeground(darkWarningColor);
- }
-
- return label;
- }
- }
}
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
index 5506779e5..8f456a9f1 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
@@ -126,7 +126,7 @@ public class GeneralPreferencesPanel extends PreferencesPanel {
//// You need to restart OpenRocket for the theme change to take effect.
final JLabel lblRestartORTheme = new JLabel();
- lblRestartORTheme.setForeground(GUIUtil.getUITheme().getDarkWarningColor());
+ lblRestartORTheme.setForeground(GUIUtil.getUITheme().getDarkErrorColor());
this.add(lblRestartORTheme, "spanx, wrap para*2, growx");
fontSizeSpinner.addChangeListener(new ChangeListener() {
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/LaunchPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/LaunchPreferencesPanel.java
index 0443c1b8a..b4eaeed33 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/LaunchPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/LaunchPreferencesPanel.java
@@ -11,7 +11,7 @@ import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.UITheme;
public class LaunchPreferencesPanel extends PreferencesPanel {
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
static {
initColors();
@@ -29,7 +29,7 @@ public class LaunchPreferencesPanel extends PreferencesPanel {
StyledLabel warning = new StyledLabel(String.format(
"%s", trans.get("pref.dlg.lbl.launchWarning")),
0.5f, StyledLabel.Style.BOLD);
- warning.setFontColor(darkWarningColor);
+ warning.setFontColor(darkErrorColor);
warning.setToolTipText(trans.get("pref.dlg.lbl.launchWarning.ttip"));
add(warning, "spanx, growx 0, gapbottom para, wrap");
@@ -44,7 +44,7 @@ public class LaunchPreferencesPanel extends PreferencesPanel {
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
}
}
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
index 66c2b6f95..264f443e5 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
@@ -97,7 +97,7 @@ public class PreferencesDialog extends JDialog {
//// Cancel button
JButton cancelButton = new SelectColorButton(trans.get("dlg.but.cancel"));
- cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip"));
+ cancelButton.setToolTipText(trans.get("SimulationConfigDialog.btn.Cancel.ttip"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -120,7 +120,7 @@ public class PreferencesDialog extends JDialog {
//// Ok button
JButton okButton = new SelectColorButton(trans.get("dlg.but.ok"));
- okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip"));
+ okButton.setToolTipText(trans.get("SimulationConfigDialog.btn.OK.ttip"));
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -213,7 +213,7 @@ public class PreferencesDialog extends JDialog {
JPanel panel = new JPanel(new MigLayout());
String msg = trans.get("PreferencesDialog.CancelOperation.msg.discardChanges");
JLabel msgLabel = new JLabel(msg);
- JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain"));
+ JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationConfigDialog.CancelOperation.checkbox.dontAskAgain"));
dontAskAgain.setSelected(false);
dontAskAgain.addItemListener(new ItemListener() {
@Override
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java
index 36e3c2dda..7a3535e5c 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java
@@ -28,7 +28,7 @@ import net.sf.openrocket.gui.widgets.SelectColorButton;
public class SimulationPreferencesPanel extends PreferencesPanel {
private static final long serialVersionUID = 7983195730016979888L;
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
static {
initColors();
@@ -93,7 +93,7 @@ public class SimulationPreferencesPanel extends PreferencesPanel {
StyledLabel warning = new StyledLabel(String.format(
"%s", trans.get("pref.dlg.lbl.launchWarning")),
0, StyledLabel.Style.BOLD);
- warning.setFontColor(darkWarningColor);
+ warning.setFontColor(darkErrorColor);
warning.setToolTipText(trans.get("pref.dlg.lbl.launchWarning.ttip"));
subsub.add(warning, "spanx, wrap para");
@@ -309,6 +309,6 @@ public class SimulationPreferencesPanel extends PreferencesPanel {
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
}
}
diff --git a/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java b/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java
index 83bc688f8..b311e7844 100644
--- a/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java
+++ b/swing/src/net/sf/openrocket/gui/figureelements/RocketInfo.java
@@ -69,7 +69,7 @@ public class RocketInfo implements FigureElement {
private static Color textColor;
private static Color dimTextColor;
- private static Color warningColor;
+ private static Color darkErrorColor;
private static Color flightDataTextActiveColor;
private static Color flightDataTextInactiveColor;
@@ -91,7 +91,7 @@ public class RocketInfo implements FigureElement {
private static void updateColors() {
textColor = GUIUtil.getUITheme().getTextColor();
dimTextColor = GUIUtil.getUITheme().getDimTextColor();
- warningColor = GUIUtil.getUITheme().getWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getErrorColor();
flightDataTextActiveColor = GUIUtil.getUITheme().getFlightDataTextActiveColor();
flightDataTextInactiveColor = GUIUtil.getUITheme().getFlightDataTextInactiveColor();
}
@@ -435,7 +435,7 @@ public class RocketInfo implements FigureElement {
float y = y2 - line * (texts.length-1);
- g2.setColor(warningColor);
+ g2.setColor(darkErrorColor);
for (GlyphVector v: texts) {
Rectangle2D rect = v.getVisualBounds();
diff --git a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
index 4a10abb00..c58576657 100644
--- a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
+++ b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java
@@ -196,7 +196,7 @@ public class BasicFrame extends JFrame {
log.debug("Constructing the BasicFrame UI");
//// Top segment, tabbed pane
- simulationPanel = new SimulationPanel(document);
+ simulationPanel = new SimulationPanel(this, document);
{
// Obtain the simulation selection model that will be used
simulationSelectionModel = simulationPanel.getSimulationListSelectionModel();
diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java
index 2aa9c4448..8bf0faca8 100644
--- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java
+++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java
@@ -1,11 +1,13 @@
package net.sf.openrocket.gui.main;
+import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;
+import java.awt.Window;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
@@ -19,15 +21,17 @@ import java.io.File;
import java.io.IOException;
import java.io.Serial;
import java.util.Comparator;
+import java.util.List;
import javax.swing.AbstractAction;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
-import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
@@ -42,17 +46,19 @@ import javax.swing.table.DefaultTableCellRenderer;
import net.sf.openrocket.arch.SystemInfo;
import net.sf.openrocket.gui.components.CsvOptionPanel;
+import net.sf.openrocket.gui.simulation.SimulationConfigDialog;
+import net.sf.openrocket.gui.util.ColorConversion;
import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.util.UITheme;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
+import net.sf.openrocket.logging.Message;
+import net.sf.openrocket.logging.Warning;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.logging.SimulationAbort;
-import net.sf.openrocket.logging.Warning;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.Simulation;
@@ -67,9 +73,7 @@ import net.sf.openrocket.gui.adaptors.ColumnTableModel;
import net.sf.openrocket.gui.adaptors.ColumnTableRowSorter;
import net.sf.openrocket.gui.adaptors.ValueColumn;
import net.sf.openrocket.gui.components.StyledLabel;
-import net.sf.openrocket.gui.simulation.SimulationEditDialog;
import net.sf.openrocket.gui.simulation.SimulationRunDialog;
-import net.sf.openrocket.gui.simulation.SimulationWarningDialog;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.gui.widgets.IconButton;
import net.sf.openrocket.l10n.Translator;
@@ -94,16 +98,10 @@ public class SimulationPanel extends JPanel {
private static final Translator trans = Application.getTranslator();
- private static final Color WARNING_COLOR = Color.RED;
- private static final String WARNING_TEXT = "\uFF01"; // Fullwidth exclamation mark
-
- private static final Color OK_COLOR = new Color(60, 150, 0);
- private static final String OK_TEXT = "\u2714"; // Heavy check mark
-
-
private RocketDescriptor descriptor = Application.getInjector().getInstance(RocketDescriptor.class);
+ private final Window parent;
private final OpenRocketDocument document;
private final ColumnTableModel simulationTableModel;
@@ -128,11 +126,21 @@ public class SimulationPanel extends JPanel {
private final SimulationAction selectedSimsExportAction;
private int[] previousSelection = null;
- private JMenuItem exportSimTableToCSVMenuItem;
- public SimulationPanel(OpenRocketDocument doc) {
+
+ private static Color dimTextColor;
+ private static Color warningColor;
+ private static Color errorColor;
+ private static Color informationColor;
+
+ static {
+ initColors();
+ }
+
+ public SimulationPanel(Window parent, OpenRocketDocument doc) {
super(new MigLayout("fill", "[grow][][][][][][grow]"));
+ this.parent = parent;
this.document = doc;
@@ -196,6 +204,7 @@ public class SimulationPanel extends JPanel {
simulationTable.setRowSorter(simulationTableSorter);
simulationTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
simulationTable.setDefaultRenderer(Object.class, new JLabelRenderer());
+ simulationTable.setDefaultRenderer(WarningsBox.class, new WarningsBoxRenderer());
simulationTableModel.setColumnWidths(simulationTable.getColumnModel());
simulationTable.setFillsViewportHeight(true);
@@ -239,12 +248,28 @@ public class SimulationPanel extends JPanel {
}
if (e.getButton() == MouseEvent.BUTTON1) {
- // Edit the simulation or plot/export
- if (e.getClickCount() == 2) {
- int selected = simulationTable.convertRowIndexToModel(selectedRow);
+ if (e.getClickCount() == 1) {
+ // Rerun the simulation
if (column == 0) {
- SimulationWarningDialog.showWarningDialog(SimulationPanel.this, document.getSimulations().get(selected));
- } else {
+ int selected = simulationTable.convertRowIndexToModel(selectedRow);
+ Simulation sim = document.getSimulations().get(selected);
+ Status status = sim.getStatus();
+
+ if (status == Status.NOT_SIMULATED || status == Status.OUTDATED) {
+ runSimulation();
+ }
+ }
+ } else if (e.getClickCount() == 2) {
+ int selected = simulationTable.convertRowIndexToModel(selectedRow);
+ // Show the warnings for the simulation
+ if (column == 1) {
+ SimulationConfigDialog dialog = new SimulationConfigDialog(parent, document, false,
+ document.getSimulations().get(selected));
+ dialog.switchToWarningsTab();
+ dialog.setVisible(true);
+ }
+ // Edit the simulation or plot/export
+ else if (column > 1) {
simulationTable.clearSelection();
simulationTable.addRowSelectionInterval(selectedRow, selectedRow);
@@ -308,6 +333,18 @@ public class SimulationPanel extends JPanel {
updateActions();
}
+ private static void initColors() {
+ updateColors();
+ UITheme.Theme.addUIThemeChangeListener(SimulationPanel::updateColors);
+ }
+
+ private static void updateColors() {
+ dimTextColor = GUIUtil.getUITheme().getDimTextColor();
+ warningColor = GUIUtil.getUITheme().getWarningColor();
+ errorColor = GUIUtil.getUITheme().getErrorColor();
+ informationColor = GUIUtil.getUITheme().getInformationColor();
+ }
+
/**
* Returns the action used for editing selected simulations.
* @return the action used for editing selected simulations.
@@ -745,73 +782,122 @@ public class SimulationPanel extends JPanel {
return simulationTable.getSelectionModel();
}
- private String getSimulationToolTip(Simulation sim, boolean includeSimName) {
- String tip;
+ private static String getSimulationStatusToolTip(Simulation sim, boolean includeSimName) {
+ StringBuilder tip;
FlightData data = sim.getSimulatedData();
- tip = "";
+ tip = new StringBuilder("");
if (includeSimName) {
- tip += "" + sim.getName() + "
";
- }
- switch (sim.getStatus()) {
- case CANT_RUN:
- tip += trans.get("simpanel.ttip.noData")+"
";
- break;
- case LOADED:
- tip += trans.get("simpanel.ttip.loaded") + "
";
- break;
- case UPTODATE:
- tip += trans.get("simpanel.ttip.uptodate") + "
";
- break;
-
- case OUTDATED:
- tip += trans.get("simpanel.ttip.outdated") + "
";
- break;
-
- case EXTERNAL:
- tip += trans.get("simpanel.ttip.external") + "
";
- return tip;
-
- case NOT_SIMULATED:
- tip += trans.get("simpanel.ttip.notSimulated");
- return tip;
+ tip.append("").append(sim.getName()).append("
");
}
if (data == null) {
- tip += trans.get("simpanel.ttip.noData");
- return tip;
+ tip.append(trans.get("simpanel.ttip.noData"));
+ return tip.toString();
+ }
+
+ switch (sim.getStatus()) {
+ case CANT_RUN:
+ tip.append(trans.get("simpanel.ttip.noData")).append("
");
+ break;
+ case LOADED:
+ tip.append(trans.get("simpanel.ttip.loaded")).append("
");
+ break;
+ case UPTODATE:
+ tip.append(trans.get("simpanel.ttip.uptodate")).append("
");
+ break;
+
+ case OUTDATED:
+ tip.append(trans.get("simpanel.ttip.outdated")).append("
");
+ break;
+
+ case EXTERNAL:
+ tip.append(trans.get("simpanel.ttip.external")).append("
");
+ return tip.toString();
+
+ case NOT_SIMULATED:
+ tip.append(trans.get("simpanel.ttip.notSimulated"));
+ return tip.toString();
}
for (int b = 0; b < data.getBranchCount(); b++) {
FlightEvent abortEvent = data.getBranch(b).getFirstEvent(FlightEvent.Type.SIM_ABORT);
- if ( abortEvent != null) {
- tip += "" + trans.get("simpanel.ttip.simAbort") + ": " +
- ((SimulationAbort)(abortEvent.getData())).toString() + "
";
+ if (abortEvent != null) {
+ tip.append("").append(trans.get("simpanel.ttip.simAbort")).append(": ").append((abortEvent.getData()).toString()).append("
");
}
}
-
- WarningSet warnings = data.getWarningSet();
- if (warnings.isEmpty()) {
- tip += trans.get("simpanel.ttip.noWarnings");
- return tip;
- }
- tip += trans.get("simpanel.ttip.warnings");
- for (Warning w : warnings) {
- tip += "
" + w.toString();
- }
-
- return tip;
+ return tip.toString();
}
- private String getSimulationToolTip(Simulation sim) {
- return getSimulationToolTip(sim, true);
+ private static String getSimulationWarningsToolTip(Simulation sim, boolean includeSimName) {
+ StringBuilder tip;
+ FlightData data = sim.getSimulatedData();
+
+ tip = new StringBuilder("");
+ if (includeSimName) {
+ tip.append("").append(sim.getName()).append("");
+ }
+
+ if (data == null) {
+ tip.append("
").append(trans.get("simpanel.ttip.noData"));
+ return tip.toString();
+ }
+
+ WarningSet warnings = data.getWarningSet();
+ if (warnings.isEmpty()) {
+ tip.append("
").append(ColorConversion.formatHTMLColor(dimTextColor, trans.get("simpanel.ttip.noWarnings")));
+ return tip.toString();
+ }
+
+ List criticalWarnings = warnings.getCriticalWarnings();
+ List normalWarnings = warnings.getNormalWarnings();
+ List informativeWarnings = warnings.getInformativeWarnings();
+
+ // Critical warnings
+ if (!criticalWarnings.isEmpty()) {
+ tip.append("
")
+ .append(ColorConversion.formatHTMLColor(errorColor, trans.get("simpanel.ttip.criticalWarnings")))
+ .append("");
+ for (Message m : criticalWarnings) {
+ tip.append("
").append(m.toString());
+ }
+ }
+
+ // Warnings
+ if (!normalWarnings.isEmpty()) {
+ tip.append("
")
+ .append(ColorConversion.formatHTMLColor(warningColor, trans.get("simpanel.ttip.normalWarnings")))
+ .append("");
+ for (Message m : normalWarnings) {
+ tip.append("
").append(m.toString());
+ }
+ }
+
+ // Informative warnings
+ if (!informativeWarnings.isEmpty()) {
+ tip.append("
")
+ .append(ColorConversion.formatHTMLColor(informationColor, trans.get("simpanel.ttip.informativeWarnings")))
+ .append("");
+ for (Message m : informativeWarnings) {
+ tip.append("
").append(m.toString());
+ }
+ }
+
+
+ return tip.toString();
+ }
+
+ private String getSimulationStatusToolTip(Simulation sim) {
+ return getSimulationStatusToolTip(sim, true);
}
private void openDialog(boolean plotMode, boolean isNewSimulation, final Simulation... sims) {
- SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, isNewSimulation, sims);
+ SimulationConfigDialog d = new SimulationConfigDialog(SwingUtilities.getWindowAncestor(this), document, isNewSimulation, sims);
if (plotMode) {
- d.setPlotMode();
+ d.switchToPlotTab();
+ } else {
+ d.switchToSettingsTab();
}
d.setVisible(true);
fireMaintainSelection();
@@ -1127,7 +1213,7 @@ public class SimulationPanel extends JPanel {
label.setBackground(table.getBackground());
label.setOpaque(true);
- label.setToolTipText(getSimulationToolTip(document.getSimulation(row)));
+ label.setToolTipText(getSimulationStatusToolTip(document.getSimulation(row)));
return label;
}
@@ -1135,7 +1221,7 @@ public class SimulationPanel extends JPanel {
isSelected, hasFocus, row, column);
if (component instanceof JComponent) {
- ((JComponent) component).setToolTipText(getSimulationToolTip(
+ ((JComponent) component).setToolTipText(getSimulationStatusToolTip(
document.getSimulation(row)));
}
return component;
@@ -1156,17 +1242,116 @@ public class SimulationPanel extends JPanel {
@Override
public String toString() {
- String text = getSimulationToolTip(simulation, false);
+ String text = getSimulationStatusToolTip(simulation, false);
return text.replace("
", "-").replaceAll("<[^>]*>","");
}
}
+ private static class WarningsBox extends Box {
+ private Simulation simulation;
+
+ public WarningsBox(Simulation simulation) {
+ super(BoxLayout.X_AXIS); // Horizontal box
+ setOpaque(false);
+ this.simulation = simulation;
+ updateContent();
+ }
+
+ public void replaceSimulation(Simulation simulation) {
+ this.simulation = simulation;
+ updateContent();
+ }
+
+ private void updateContent() {
+ removeAll(); // Clear existing content before update
+ setToolTipText("");
+
+ if (simulation == null) {
+ revalidate();
+ return;
+ }
+
+ // Update the tooltip text
+ String ttip = getSimulationWarningsToolTip(simulation, true);
+ setToolTipText(ttip);
+
+ WarningSet warnings = simulation.getSimulatedWarnings();
+
+ if (warnings == null || warnings.isEmpty()) {
+ revalidate();
+ return;
+ }
+
+ int nrOfCriticalWarnings = warnings.getNrOfCriticalWarnings();
+ int nrOfNormalWarnings = warnings.getNrOfNormalWarnings();
+ int nrOfInfoWarnings = warnings.getNrOfInformativeWarnings();
+
+ if (nrOfCriticalWarnings > 0) {
+ add(new JLabel(nrOfCriticalWarnings + " "));
+ add(new JLabel(Icons.WARNING_HIGH));
+ }
+
+ if (nrOfCriticalWarnings > 0 && nrOfNormalWarnings > 0) {
+ add(new JLabel(", "));
+ }
+
+ if (nrOfNormalWarnings > 0) {
+ add(new JLabel(nrOfNormalWarnings + " "));
+ add(new JLabel(Icons.WARNING_NORMAL));
+ }
+
+ if ((nrOfCriticalWarnings > 0 || nrOfNormalWarnings > 0) && nrOfInfoWarnings > 0) {
+ add(new JLabel(", "));
+ }
+
+ if (nrOfInfoWarnings > 0) {
+ add(new JLabel(nrOfInfoWarnings + " "));
+ add(new JLabel(Icons.WARNING_LOW));
+ }
+
+ revalidate(); // Notify layout manager of changes
+ }
+ }
+
+ public static class WarningsBoxRenderer extends DefaultTableCellRenderer {
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ if (value instanceof WarningsBox box) {
+ // Wrap the box in a panel with BorderLayout to allow alignment
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setToolTipText(box.getToolTipText());
+ panel.add(box, BorderLayout.EAST); // Align to the right within the panel
+ panel.setOpaque(true);
+ if (isSelected) {
+ panel.setBackground(table.getSelectionBackground());
+ updateBoxColors(box, table.getSelectionForeground());
+ } else {
+ panel.setBackground(table.getBackground());
+ updateBoxColors(box, table.getForeground());
+ }
+
+ return panel;
+ }
+ return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+ }
+
+ private void updateBoxColors(WarningsBox box, Color foreground) {
+ // Set the foreground for the box and its child components
+ box.setForeground(foreground); // Assuming this sets the box's own foreground
+ for (Component comp : box.getComponents()) {
+ if (comp instanceof JLabel) {
+ comp.setForeground(foreground);
+ }
+ }
+ }
+ }
+
private class SimulationTableModel extends ColumnTableModel {
private static final long serialVersionUID = 8686456963492628476L;
public SimulationTableModel() {
super(
- //// Status and warning column
+ //// Status column
new Column("") {
private StatusLabel label = null;
@@ -1190,31 +1375,12 @@ public class SimulationPanel extends JPanel {
Simulation.Status status = simulation.getStatus();
label.setIcon(Icons.SIMULATION_STATUS_ICON_MAP.get(status));
-
- // Set warning marker
- if (status == Simulation.Status.NOT_SIMULATED ||
- status == Simulation.Status.EXTERNAL) {
- label.setText("");
- } else {
-
- WarningSet w = document.getSimulation(row).getSimulatedWarnings();
- if (w == null) {
- label.setText("");
- } else if (w.isEmpty()) {
- label.setForeground(OK_COLOR);
- label.setText(OK_TEXT);
- } else {
- label.setForeground(WARNING_COLOR);
- label.setText(WARNING_TEXT);
- }
- }
-
return label;
}
@Override
public int getExactWidth() {
- return 36;
+ return 26;
}
@Override
@@ -1223,6 +1389,38 @@ public class SimulationPanel extends JPanel {
}
},
+ //// Warnings column
+ new Column(trans.get("simpanel.col.Warnings")) {
+ private WarningsBox box = null;
+
+ @Override
+ public Object getValueAt(int row) {
+ if (row < 0 || row >= document.getSimulationCount())
+ return null;
+
+ Simulation simulation = document.getSimulation(row);
+
+ // Initialize the box
+ if (box == null) {
+ box = new WarningsBox(simulation);
+ } else {
+ box.replaceSimulation(simulation);
+ }
+
+ return box;
+ }
+
+ @Override
+ public int getDefaultWidth() {
+ return 70;
+ }
+
+ @Override
+ public Class> getColumnClass() {
+ return WarningsBox.class;
+ }
+ },
+
//// Simulation name
//// Name
new Column(trans.get("simpanel.col.Name")) {
diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
index 83096c3cc..292f076cb 100644
--- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
+++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
@@ -45,7 +45,7 @@ import org.jfree.chart.JFreeChart;
public class SimulationPlotDialog extends JDialog {
private static final Translator trans = Application.getTranslator();
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
private final JCheckBox checkErrors;
static {
@@ -82,7 +82,7 @@ public class SimulationPlotDialog extends JDialog {
// Add warning if X axis type is not time
if (config.getDomainAxisType() != FlightDataType.TYPE_TIME) {
JLabel msg = new StyledLabel(trans.get("PlotDialog.lbl.timeSeriesWarning"), -2);
- msg.setForeground(darkWarningColor);
+ msg.setForeground(darkErrorColor);
panel.add(msg, "wrap");
}
@@ -207,7 +207,7 @@ public class SimulationPlotDialog extends JDialog {
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
}
private boolean doPNGExport(ChartPanel chartPanel, JFreeChart chart){
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationConfigDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationConfigDialog.java
new file mode 100644
index 000000000..0c60befd5
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationConfigDialog.java
@@ -0,0 +1,492 @@
+package net.sf.openrocket.gui.simulation;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.document.events.DocumentChangeEvent;
+import net.sf.openrocket.gui.components.ConfigurationComboBox;
+import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.UITheme;
+import net.sf.openrocket.gui.widgets.SelectColorButton;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.rocketcomponent.FlightConfiguration;
+import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.simulation.extension.SimulationExtension;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.startup.Preferences;
+import net.sf.openrocket.util.StateChangeListener;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.awt.Color;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
+
+public class SimulationConfigDialog extends JDialog {
+ private static final long serialVersionUID = -1068127685642912715L;
+
+ private final Window parentWindow;
+ private final Simulation[] simulationList;
+ private final OpenRocketDocument document;
+ private final JTabbedPane tabbedPane;
+ private JButton okButton;
+ private JButton cancelButton;
+ private static final Translator trans = Application.getTranslator();
+ private static final Preferences preferences = Application.getPreferences();
+
+
+ private final WindowListener applyChangesToSimsListener;
+ private final Simulation initialSim; // A copy of the first selected simulation before it was modified
+ private final boolean initialIsSaved; // Whether the document was saved before the dialog was opened
+ private boolean isModified = false; // Whether the simulation has been modified
+ private final boolean isNewSimulation; // Whether you are editing a new simulation, or an existing one
+
+ private static final int SETTINGS_IDX = 0;
+ private static final int WARNINGS_IDX = 1;
+ private static final int PLOT_IDX = 2;
+ private static final int EXPORT_IDX = 3;
+
+ private final SimulationPlotPanel plotTab;
+ private final SimulationExportPanel exportTab;
+
+ private static Color multiCompEditColor;
+
+ static {
+ initColors();
+ }
+
+ public SimulationConfigDialog(Window parent, final OpenRocketDocument document, boolean isNewSimulation, Simulation... sims) {
+ super(parent, sims.length == 1 ? trans.get("simedtdlg.title.Editsim") : trans.get("simedtdlg.title.MultiSimEdit"),
+ JDialog.ModalityType.DOCUMENT_MODAL);
+ this.document = document;
+ this.parentWindow = parent;
+ this.simulationList = sims;
+ this.initialSim = simulationList[0].clone();
+ this.initialIsSaved = document.isSaved();
+ this.isNewSimulation = isNewSimulation;
+
+ simulationList[0].addChangeListener(new StateChangeListener() {
+ @Override
+ public void stateChanged(EventObject e) {
+ isModified = true;
+ setTitle("* " + getTitle()); // Add component changed indicator to the title
+ simulationList[0].removeChangeListener(this);
+ }
+ });
+
+ final JPanel contentPanel = new JPanel(new MigLayout("fill"));
+
+ // ======== Top panel ========
+ addTopPanel(document, contentPanel);
+
+
+ // ======== Tabbed pane ========
+ this.tabbedPane = new JTabbedPane();
+
+ //// Simulation Settings
+ final SimulationSettingsPanel settingsTab = new SimulationSettingsPanel(document, simulationList[0]);
+ tabbedPane.addTab(trans.get("SimulationConfigDialog.tab.Settings"), settingsTab);
+
+ //// Simulation Warnings
+ final SimulationWarningsPanel warningsTab = new SimulationWarningsPanel(simulationList[0]);
+ tabbedPane.addTab(trans.get("SimulationConfigDialog.tab.Warnings"), warningsTab);
+ if (isMultiCompEdit()) {
+ tabbedPane.setEnabledAt(WARNINGS_IDX, false);
+ tabbedPane.setToolTipTextAt(WARNINGS_IDX, trans.get("SimulationConfigDialog.tab.warnDis.ttip"));
+ }
+
+ //// Plot data
+ boolean hasData = simulationList[0].hasSimulationData();
+ if (hasData) {
+ this.plotTab = new SimulationPlotPanel(simulationList[0]);
+ } else {
+ this.plotTab = null;
+ }
+ tabbedPane.addTab(trans.get("SimulationConfigDialog.tab.Plotdata"), plotTab);
+ if (isMultiCompEdit() || !hasData) {
+ tabbedPane.setEnabledAt(PLOT_IDX, false);
+ String ttip = hasData ? trans.get("SimulationConfigDialog.tab.plotDis.ttip") : trans.get("SimulationConfigDialog.tab.plotNoData.ttip");
+ tabbedPane.setToolTipTextAt(PLOT_IDX, ttip);
+ }
+
+ //// Export data
+ if (hasData) {
+ this.exportTab = new SimulationExportPanel(simulationList[0]);
+ } else {
+ this.exportTab = null;
+ }
+ tabbedPane.addTab(trans.get("SimulationConfigDialog.tab.Exportdata"), exportTab);
+ if (isMultiCompEdit() || !hasData) {
+ tabbedPane.setEnabledAt(EXPORT_IDX, false);
+ String ttip = hasData ? trans.get("SimulationConfigDialog.tab.expDis.ttip") : trans.get("SimulationConfigDialog.tab.expNoData.ttip");
+ tabbedPane.setToolTipTextAt(EXPORT_IDX, ttip);
+ }
+
+ contentPanel.add(tabbedPane, "grow, wrap");
+
+
+ // ======== Bottom panel ========
+ addBottomPanel(contentPanel);
+
+
+ tabbedPane.addChangeListener(new ChangeListener() {
+
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ if (okButton == null) {
+ return;
+ }
+ int selectedIndex = tabbedPane.getSelectedIndex();
+ switch (selectedIndex) {
+ case SETTINGS_IDX:
+ okButton.setText(trans.get("dlg.but.ok"));
+ cancelButton.setText(trans.get("dlg.but.cancel"));
+ cancelButton.setVisible(true);
+ SimulationConfigDialog.this.revalidate();
+ break;
+ case WARNINGS_IDX:
+ okButton.setText(trans.get("dlg.but.close"));
+ cancelButton.setVisible(false);
+ SimulationConfigDialog.this.revalidate();
+ break;
+ case PLOT_IDX:
+ okButton.setText(trans.get("SimulationConfigDialog.btn.plot"));
+ cancelButton.setText(trans.get("dlg.but.close"));
+ cancelButton.setVisible(true);
+ SimulationConfigDialog.this.revalidate();
+ break;
+ case EXPORT_IDX:
+ okButton.setText(trans.get("SimulationConfigDialog.btn.export"));
+ cancelButton.setText(trans.get("dlg.but.close"));
+ cancelButton.setVisible(true);
+ SimulationConfigDialog.this.revalidate();
+ break;
+ }
+ }
+
+ });
+
+ this.add(contentPanel);
+ this.validate();
+ this.pack();
+
+ this.setLocationByPlatform(true);
+
+ this.applyChangesToSimsListener = new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ copyChangesToAllSims();
+ }
+ };
+ this.addWindowListener(applyChangesToSimsListener);
+
+ GUIUtil.setDisposableDialogOptions(this, null);
+ }
+
+ private static void initColors() {
+ updateColors();
+ UITheme.Theme.addUIThemeChangeListener(SimulationConfigDialog::updateColors);
+ }
+
+ private static void updateColors() {
+ multiCompEditColor = GUIUtil.getUITheme().getMultiCompEditColor();
+ }
+
+ public void switchToSettingsTab() {
+ tabbedPane.setSelectedIndex(SETTINGS_IDX);
+ }
+
+ public void switchToWarningsTab() {
+ tabbedPane.setSelectedIndex(WARNINGS_IDX);
+ }
+
+ public void switchToPlotTab() {
+ tabbedPane.setSelectedIndex(PLOT_IDX);
+ }
+
+ public void switchToExportTab() {
+ tabbedPane.setSelectedIndex(EXPORT_IDX);
+ }
+
+ private void addTopPanel(OpenRocketDocument document, JPanel contentPanel) {
+ JPanel topPanel = new JPanel(new MigLayout("fill, ins 0"));
+
+ //// Name:
+ topPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "growx 0, gapright para");
+ final JTextField field = new JTextField(simulationList[0].getName());
+ field.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ setText();
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ setText();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ setText();
+ }
+
+ private void setText() {
+ String name = field.getText();
+ if (name == null || name.equals(""))
+ return;
+ simulationList[0].setName(name);
+
+ }
+ });
+ topPanel.add(field, "growx, wrap");
+
+ //// Flight selector
+ //// Flight configuration:
+ JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg"));
+ //// Select the motor configuration to use.
+ label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg"));
+ topPanel.add(label, "growx 0, gapright para");
+
+ final Rocket rkt = document.getRocket();
+ final FlightConfiguration config = rkt.getFlightConfiguration(simulationList[0].getFlightConfigurationId());
+ final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt, false);
+ configComboBox.setSelectedItem(config);
+
+ //// Select the motor configuration to use.
+ configComboBox.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg"));
+ configComboBox.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ FlightConfiguration config = (FlightConfiguration)configComboBox.getSelectedItem();
+ FlightConfigurationId id = config.getId();
+
+ simulationList[0].setFlightConfigurationId( id );
+ }
+ });
+ topPanel.add(configComboBox, "span");
+
+ topPanel.add(new JPanel(), "growx, wrap");
+
+ contentPanel.add(topPanel, "growx, wrap");
+ }
+
+ private void addBottomPanel(JPanel contentPanel) {
+ final JPanel bottomPanel = new JPanel(new MigLayout("fill, ins 0"));
+
+ //// Multi-simulation edit
+ if (isMultiCompEdit()) {
+ StyledLabel multiSimEditLabel = new StyledLabel("", -1, StyledLabel.Style.BOLD);
+ multiSimEditLabel.setFontColor(multiCompEditColor);
+ multiSimEditLabel.setText(trans.get("simedtdlg.title.MultiSimEdit"));
+ StringBuilder components = new StringBuilder(trans.get("simedtdlg.title.MultiSimEdit.ttip"));
+ for (int i = 0; i < simulationList.length; i++) {
+ if (i < simulationList.length - 1) {
+ components.append(simulationList[i].getName()).append(", ");
+ } else {
+ components.append(simulationList[i].getName());
+ }
+ }
+ multiSimEditLabel.setToolTipText(components.toString());
+ bottomPanel.add(multiSimEditLabel, "align left");
+ }
+
+ //// Run simulation button
+ // TODO: disable when sim is up to date?
+ /*JButton button = new SelectColorButton(trans.get("SimulationEditDialog.btn.simulateAndPlot"));
+ if (!isSingleEdit()) {
+ button.setText(trans.get("SimulationEditDialog.btn.simulate"));
+ }
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ copyChangesToAllSims();
+ SimulationRunDialog dialog = SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulationList);
+ if (allowsPlotMode() && dialog.isAllSimulationsSuccessful()) {
+ refreshView();
+ setPlotMode();
+ }
+ }
+ });
+ simEditPanel.add(button, "align right, gapright 10lp, tag ok");*/
+
+ //// Cancel button
+ this.cancelButton = new SelectColorButton(trans.get("dlg.but.cancel"));
+ this.cancelButton.setToolTipText(trans.get("SimulationConfigDialog.btn.Cancel.ttip"));
+ this.cancelButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (tabbedPane.getSelectedIndex() == SETTINGS_IDX) {
+ cancelSimEdit();
+ } else {
+ // Normal close action
+ closeDialog();
+ }
+
+ // TODO: include plot/export undo?
+ }
+ });
+ bottomPanel.add(this.cancelButton, "split 2, tag ok");
+
+ //// Ok button
+ this.okButton = new SelectColorButton(trans.get("dlg.but.ok"));
+ this.okButton.setToolTipText(trans.get("SimulationConfigDialog.btn.OK.ttip"));
+ this.okButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ copyChangesToAllSims();
+
+ // Run outdated simulations
+ Simulation[] outdatedSims = getOutdatedSimulations();
+ if (outdatedSims.length > 0) {
+ new SimulationRunDialog(SimulationConfigDialog.this.parentWindow, document, outdatedSims).setVisible(true);
+ }
+
+ int tabIdx = tabbedPane.getSelectedIndex();
+ if (tabIdx == PLOT_IDX) {
+ if (plotTab == null) {
+ closeDialog();
+ return;
+ }
+ JDialog plot = plotTab.doPlot(SimulationConfigDialog.this.parentWindow);
+ if (plot != null) {
+ plot.setVisible(true);
+ }
+ closeDialog();
+ return;
+ } else if (tabIdx == EXPORT_IDX) {
+ if (exportTab == null || exportTab.doExport()) {
+ closeDialog();
+ }
+ return;
+ }
+
+ closeDialog();
+ }
+ });
+ bottomPanel.add(this.okButton, "tag ok");
+
+ contentPanel.add(bottomPanel, "growx, wrap");
+ }
+
+ private void copyChangesToAllSims() {
+ if (isMultiCompEdit()) {
+ for (int i = 1; i < simulationList.length; i++) {
+ simulationList[i].getOptions().copyConditionsFrom(simulationList[0].getOptions());
+ simulationList[i].getSimulationExtensions().clear();
+ for (SimulationExtension c : simulationList[0].getSimulationExtensions()) {
+ simulationList[i].getSimulationExtensions().add(c.clone());
+ }
+ }
+ }
+ }
+
+ private Simulation[] getOutdatedSimulations() {
+ List outdated = new ArrayList<>();
+ for (Simulation sim : simulationList) {
+ if (!Simulation.isStatusUpToDate(sim.getStatus())) {
+ outdated.add(sim);
+ }
+ }
+ return outdated.toArray(new Simulation[0]);
+ }
+
+ private boolean isMultiCompEdit() {
+ return simulationList.length > 1;
+ }
+
+ private void closeDialog() {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ SimulationConfigDialog.this.removeWindowListener(applyChangesToSimsListener);
+ SimulationConfigDialog.this.dispose();
+ }
+ });
+ }
+
+ private JPanel createCancelOperationContent() {
+ JPanel panel = new JPanel(new MigLayout());
+ String msg = isNewSimulation ? trans.get("SimulationConfigDialog.CancelOperation.msg.undoAdd") :
+ trans.get("SimulationConfigDialog.CancelOperation.msg.discardChanges");
+ JLabel msgLabel = new JLabel(msg);
+ JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationConfigDialog.CancelOperation.checkbox.dontAskAgain"));
+ dontAskAgain.setSelected(false);
+ dontAskAgain.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ preferences.setShowDiscardSimulationConfirmation(false);
+ }
+ // Unselected state should be not be possible and thus not be handled
+ }
+ });
+
+ panel.add(msgLabel, "left, wrap");
+ panel.add(dontAskAgain, "left, gaptop para");
+
+ return panel;
+ }
+
+ private void cancelSimEdit() {
+ // Don't do anything on cancel if you are editing an existing simulation, and it is not modified
+ if (!isNewSimulation && !isModified) {
+ closeDialog();
+ return;
+ }
+
+ // Apply the cancel operation if set to auto discard in preferences
+ if (!preferences.isShowDiscardSimulationConfirmation()) {
+ discardChanges();
+ return;
+ }
+
+ // Yes/No dialog: Are you sure you want to discard your changes?
+ JPanel msg = createCancelOperationContent();
+ int resultYesNo = JOptionPane.showConfirmDialog(SimulationConfigDialog.this, msg,
+ trans.get("SimulationConfigDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
+ if (resultYesNo == JOptionPane.YES_OPTION) {
+ discardChanges();
+ }
+ }
+
+ private void discardChanges() {
+ if (isNewSimulation) {
+ document.removeSimulation(simulationList[0]);
+ } else {
+ undoSimulationChanges();
+ }
+ document.setSaved(this.initialIsSaved); // Restore the saved state of the document
+ document.fireDocumentChangeEvent(new DocumentChangeEvent(this));
+
+ closeDialog();
+ }
+
+ private void undoSimulationChanges() {
+ if (simulationList == null || simulationList.length == 0) {
+ return;
+ }
+ simulationList[0].loadFrom(initialSim);
+ }
+}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
deleted file mode 100644
index 51fd38235..000000000
--- a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java
+++ /dev/null
@@ -1,476 +0,0 @@
-package net.sf.openrocket.gui.simulation;
-
-
-import java.awt.CardLayout;
-import java.awt.Color;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
-import java.util.EventObject;
-
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JTabbedPane;
-import javax.swing.JTextField;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.document.events.DocumentChangeEvent;
-import net.sf.openrocket.gui.components.ConfigurationComboBox;
-import net.sf.openrocket.gui.components.StyledLabel;
-import net.sf.openrocket.gui.util.GUIUtil;
-import net.sf.openrocket.gui.util.UITheme;
-import net.sf.openrocket.gui.widgets.SelectColorButton;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.rocketcomponent.FlightConfiguration;
-import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.simulation.extension.SimulationExtension;
-import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.startup.Preferences;
-import net.sf.openrocket.util.StateChangeListener;
-
-
-public class SimulationEditDialog extends JDialog {
- private static final long serialVersionUID = -4468157685542912715L;
- private final Window parentWindow;
- private final Simulation[] simulationList;
- private final OpenRocketDocument document;
- private static final Translator trans = Application.getTranslator();
- private static final Preferences preferences = Application.getPreferences();
-
- JPanel cards;
- private final static String EDITMODE = "EDIT";
- private final static String PLOTMODE = "PLOT";
-
- private final WindowListener applyChangesToSimsListener;
- private final Simulation initialSim; // A copy of the first selected simulation before it was modified
- private final boolean initialIsSaved; // Whether the document was saved before the dialog was opened
- private boolean isModified = false; // Whether the simulation has been modified
- private final boolean isNewSimulation; // Whether you are editing a new simulation, or an existing one
-
- private static Color multiCompEditColor;
-
- static {
- initColors();
- }
-
- public SimulationEditDialog(Window parent, final OpenRocketDocument document, boolean isNewSimulation, Simulation... sims) {
- //// Edit simulation
- super(parent, sims.length == 1 ? trans.get("simedtdlg.title.Editsim") : trans.get("simedtdlg.title.MultiSimEdit"),
- JDialog.ModalityType.DOCUMENT_MODAL);
- this.document = document;
- this.parentWindow = parent;
- this.simulationList = sims;
- this.initialSim = simulationList[0].clone();
- this.initialIsSaved = document.isSaved();
- this.isNewSimulation = isNewSimulation;
-
- simulationList[0].addChangeListener(new StateChangeListener() {
- @Override
- public void stateChanged(EventObject e) {
- isModified = true;
- setTitle("* " + getTitle()); // Add component changed indicator to the title
- simulationList[0].removeChangeListener(this);
- }
- });
-
- this.cards = new JPanel(new CardLayout());
- this.add(cards);
- buildEditCard();
- buildPlotCard();
-
- this.validate();
- this.pack();
-
- this.setLocationByPlatform(true);
-
- this.applyChangesToSimsListener = new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- copyChangesToAllSims();
- }
- };
- this.addWindowListener(applyChangesToSimsListener);
-
- GUIUtil.setDisposableDialogOptions(this, null);
- }
-
- private static void initColors() {
- updateColors();
- UITheme.Theme.addUIThemeChangeListener(SimulationEditDialog::updateColors);
- }
-
- private static void updateColors() {
- multiCompEditColor = GUIUtil.getUITheme().getMultiCompEditColor();
- }
-
- private boolean isSingleEdit() {
- return simulationList.length == 1;
- }
-
- private boolean allowsPlotMode() {
- return simulationList.length == 1 && simulationList[0].hasSimulationData();
- }
-
- public void setEditMode() {
- String baseTitle = simulationList.length == 1 ?
- trans.get("simedtdlg.title.Editsim") : trans.get("simedtdlg.title.MultiSimEdit");
- setTitle((isModified ? "* " : "") + baseTitle);
- CardLayout cl = (CardLayout) (cards.getLayout());
- cl.show(cards, EDITMODE);
- cards.validate();
- this.addWindowListener(applyChangesToSimsListener);
- }
-
- public void setPlotMode() {
- if (!allowsPlotMode()) {
- return;
- }
- this.removeWindowListener(applyChangesToSimsListener);
- setTitle((isModified ? "* " : "") + trans.get("simplotpanel.title.Plotsim"));
- CardLayout cl = (CardLayout) (cards.getLayout());
- cl.show(cards, PLOTMODE);
- cards.validate();
- }
-
- private void copyChangesToAllSims() {
- if (simulationList.length > 1) {
- for (int i = 1; i < simulationList.length; i++) {
- simulationList[i].getOptions().copyConditionsFrom(simulationList[0].getOptions());
- simulationList[i].getSimulationExtensions().clear();
- for (SimulationExtension c : simulationList[0].getSimulationExtensions()) {
- simulationList[i].getSimulationExtensions().add(c.clone());
- }
- }
- }
- }
-
- private void refreshView() {
- cards.removeAll();
- buildEditCard();
- buildPlotCard();
- this.validate();
- }
-
- private void buildEditCard() {
- JPanel simEditPanel = new JPanel(new MigLayout("fill, hidemode 1"));
-
- if (isSingleEdit()) {
- JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
-
- //// Simulation name:
- panel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "growx 0, gapright para");
- final JTextField field = new JTextField(simulationList[0].getName());
- field.getDocument().addDocumentListener(new DocumentListener() {
- @Override
- public void changedUpdate(DocumentEvent e) {
- setText();
- }
-
- @Override
- public void insertUpdate(DocumentEvent e) {
- setText();
- }
-
- @Override
- public void removeUpdate(DocumentEvent e) {
- setText();
- }
-
- private void setText() {
- String name = field.getText();
- if (name == null || name.equals(""))
- return;
- simulationList[0].setName(name);
-
- }
- });
- panel.add(field, "growx, wrap");
-
- //// Flight selector
- //// Flight configuration:
- JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg"));
- //// Select the motor configuration to use.
- label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg"));
- panel.add(label, "growx 0, gapright para");
-
- final Rocket rkt = document.getRocket();
- final FlightConfiguration config = rkt.getFlightConfiguration(simulationList[0].getFlightConfigurationId());
- final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt, false);
- configComboBox.setSelectedItem(config);
-
- //// Select the motor configuration to use.
- configComboBox.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg"));
- configComboBox.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- FlightConfiguration config = (FlightConfiguration)configComboBox.getSelectedItem();
- FlightConfigurationId id = config.getId();
-
- simulationList[0].setFlightConfigurationId( id );
- }
- });
- panel.add(configComboBox, "span");
-
- panel.add(new JPanel(), "growx, wrap");
-
- simEditPanel.add(panel, "growx, wrap");
- }
- JTabbedPane tabbedPane = new JTabbedPane();
-
- //// Launch conditions
- tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulationList[0]));
- //// Simulation options
- tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(document, simulationList[0]));
-
- tabbedPane.setSelectedIndex(0);
-
- simEditPanel.add(tabbedPane, "spanx, grow, wrap");
-
-
- //// Open Plot button
- JButton button = new SelectColorButton(trans.get("SimulationEditDialog.btn.plot") + " >>");
- button.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- SimulationEditDialog.this.setPlotMode();
- }
-
- });
- simEditPanel.add(button, "spanx, split 5, align left");
- if (allowsPlotMode()) {
- button.setVisible(true);
- } else {
- button.setVisible(false);
- }
-
- //// Multi-simulation edit
- if (simulationList.length > 1) {
- StyledLabel multiSimEditLabel = new StyledLabel("", -1, StyledLabel.Style.BOLD);
- multiSimEditLabel.setFontColor(multiCompEditColor);
- multiSimEditLabel.setText(trans.get("simedtdlg.title.MultiSimEdit"));
- StringBuilder components = new StringBuilder(trans.get("simedtdlg.title.MultiSimEdit.ttip"));
- for (int i = 0; i < simulationList.length; i++) {
- if (i < simulationList.length - 1) {
- components.append(simulationList[i].getName()).append(", ");
- } else {
- components.append(simulationList[i].getName());
- }
- }
- multiSimEditLabel.setToolTipText(components.toString());
- simEditPanel.add(multiSimEditLabel, "align left");
- }
-
- //// Run simulation button
- button = new SelectColorButton(trans.get("SimulationEditDialog.btn.simulateAndPlot"));
- if (!isSingleEdit()) {
- button.setText(trans.get("SimulationEditDialog.btn.simulate"));
- }
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- copyChangesToAllSims();
- SimulationRunDialog dialog = SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulationList);
- if (allowsPlotMode() && dialog.isAllSimulationsSuccessful()) {
- refreshView();
- setPlotMode();
- }
- }
- });
- simEditPanel.add(button, "align right, gapright 10lp, tag ok");
-
- //// Cancel button
- JButton cancelButton = new SelectColorButton(trans.get("dlg.but.cancel"));
- cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip"));
- cancelButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- // Don't do anything on cancel if you are editing an existing simulation, and it is not modified
- if (!isNewSimulation && !isModified) {
- SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener);
- SimulationEditDialog.this.dispose();
- return;
- }
-
- // Apply the cancel operation if set to auto discard in preferences
- if (!preferences.isShowDiscardSimulationConfirmation()) {
- discardChanges();
- return;
- }
-
- // Yes/No dialog: Are you sure you want to discard your changes?
- JPanel msg = createCancelOperationContent();
- int resultYesNo = JOptionPane.showConfirmDialog(SimulationEditDialog.this, msg,
- trans.get("SimulationEditDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
- if (resultYesNo == JOptionPane.YES_OPTION) {
- discardChanges();
- }
- }
- });
- simEditPanel.add(cancelButton, "tag ok");
-
- //// Ok button
- JButton okButton = new SelectColorButton(trans.get("dlg.but.ok"));
- okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip"));
- okButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- copyChangesToAllSims();
- SimulationEditDialog.this.dispose();
- }
- });
- simEditPanel.add(okButton, "tag ok");
-
- cards.add(simEditPanel, EDITMODE);
- }
-
- private void buildPlotCard() {
- if (allowsPlotMode()) {
- JPanel plotExportPanel = new JPanel(new MigLayout("fill"));
-
- //// Simulation name:
- plotExportPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink");
- final JTextField field = new JTextField(simulationList[0].getName());
- field.setEditable(false);
- plotExportPanel.add(field, "shrinky, growx, wrap");
-
- final JTabbedPane tabbedPane = new JTabbedPane();
-
- //// Plot data
- final SimulationPlotPanel plotTab = new SimulationPlotPanel(simulationList[0]);
- tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab);
- //// Export data
- final SimulationExportPanel exportTab = new SimulationExportPanel(simulationList[0]);
- tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab);
-
- plotExportPanel.add(tabbedPane, "grow, wrap");
-
- JButton button = new SelectColorButton("<< " + trans.get("SimulationEditDialog.btn.edit"));
- button.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- SimulationEditDialog.this.setEditMode();
- }
-
- });
-
- plotExportPanel.add(button, "spanx, split 3, align left");
-
- final JButton ok = new SelectColorButton(trans.get("SimulationEditDialog.btn.plot"));
-
- tabbedPane.addChangeListener(new ChangeListener() {
-
- @Override
- public void stateChanged(ChangeEvent e) {
- int selectedIndex = tabbedPane.getSelectedIndex();
- switch (selectedIndex) {
- case 0:
- ok.setText(trans.get("SimulationEditDialog.btn.plot"));
- plotExportPanel.revalidate();
- break;
- case 1:
- ok.setText(trans.get("SimulationEditDialog.btn.export"));
- plotExportPanel.revalidate();
- break;
- }
- }
-
- });
-
- ok.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- // If the simulation is out of date, run the simulation.
- if (!Simulation.isStatusUpToDate(simulationList[0].getStatus())) {
- new SimulationRunDialog(SimulationEditDialog.this.parentWindow, document, simulationList[0]).setVisible(true);
- }
-
- if (tabbedPane.getSelectedIndex() == 0) {
- JDialog plot = plotTab.doPlot(SimulationEditDialog.this.parentWindow);
- if (plot != null) {
- plot.setVisible(true);
- }
- } else {
- if (exportTab.doExport()) {
- SimulationEditDialog.this.dispose();
- }
- }
- }
- });
- plotExportPanel.add(ok, "tag ok, split 2");
-
- //// Close button
- JButton close = new SelectColorButton(trans.get("dlg.but.close"));
- close.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- SimulationEditDialog.this.dispose();
- }
- });
- plotExportPanel.add(close, "tag cancel");
- //plotExportPanel.validate();
- cards.add(plotExportPanel, PLOTMODE);
-
- }
- }
-
- private JPanel createCancelOperationContent() {
- JPanel panel = new JPanel(new MigLayout());
- String msg = isNewSimulation ? trans.get("SimulationEditDialog.CancelOperation.msg.undoAdd") :
- trans.get("SimulationEditDialog.CancelOperation.msg.discardChanges");
- JLabel msgLabel = new JLabel(msg);
- JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain"));
- dontAskAgain.setSelected(false);
- dontAskAgain.addItemListener(new ItemListener() {
- @Override
- public void itemStateChanged(ItemEvent e) {
- if (e.getStateChange() == ItemEvent.SELECTED) {
- preferences.setShowDiscardSimulationConfirmation(false);
- }
- // Unselected state should be not be possible and thus not be handled
- }
- });
-
- panel.add(msgLabel, "left, wrap");
- panel.add(dontAskAgain, "left, gaptop para");
-
- return panel;
- }
-
- private void discardChanges() {
- if (isNewSimulation) {
- document.removeSimulation(simulationList[0]);
- } else {
- undoSimulationChanges();
- }
- document.setSaved(this.initialIsSaved); // Restore the saved state of the document
- document.fireDocumentChangeEvent(new DocumentChangeEvent(this));
-
- SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener);
- SimulationEditDialog.this.dispose();
- }
-
- private void undoSimulationChanges() {
- if (simulationList == null || simulationList.length == 0) {
- return;
- }
- simulationList[0].loadFrom(initialSim);
- }
-}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
index 938f5948d..5e4db1160 100644
--- a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
+++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
@@ -5,6 +5,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
+import java.io.Serial;
import java.util.Arrays;
import java.util.EnumSet;
@@ -51,6 +52,7 @@ import net.sf.openrocket.gui.widgets.SelectColorButton;
* @author Sampo Niskanen
*/
public class SimulationPlotPanel extends JPanel {
+ @Serial
private static final long serialVersionUID = -2227129713185477998L;
private static final Translator trans = Application.getTranslator();
@@ -110,7 +112,7 @@ public class SimulationPlotPanel extends JPanel {
private DescriptionArea simPlotPanelDesc;
- private static java.awt.Color darkWarningColor;
+ private static java.awt.Color darkErrorColor;
private static Border border;
static {
@@ -213,7 +215,7 @@ public class SimulationPlotPanel extends JPanel {
//// The data will be plotted in time order even if the X axis type is not time.
simPlotPanelDesc = new DescriptionArea("", 2, -2f, false);
simPlotPanelDesc.setVisible(false);
- simPlotPanelDesc.setForeground(darkWarningColor);
+ simPlotPanelDesc.setForeground(darkErrorColor);
simPlotPanelDesc.setViewportBorder(BorderFactory.createEmptyBorder());
this.add(simPlotPanelDesc, "width 1px, growx 1, wrap unrel");
@@ -393,7 +395,7 @@ public class SimulationPlotPanel extends JPanel {
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
border = GUIUtil.getUITheme().getBorder();
}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationSettingsPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationSettingsPanel.java
new file mode 100644
index 000000000..466d4a3e6
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationSettingsPanel.java
@@ -0,0 +1,36 @@
+package net.sf.openrocket.gui.simulation;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
+
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import java.io.Serial;
+
+public class SimulationSettingsPanel extends JPanel {
+ @Serial
+ private static final long serialVersionUID = -2114129713185477998L;
+
+ private static final Translator trans = Application.getTranslator();
+
+ public SimulationSettingsPanel(final OpenRocketDocument document, final Simulation simulation) {
+ super(new MigLayout("fill"));
+
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ //// Launch conditions
+ tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulation));
+
+ //// Simulation options
+ tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(document, simulation));
+
+ tabbedPane.setSelectedIndex(0);
+
+ this.add(tabbedPane, "spanx, grow, wrap");
+ }
+
+
+}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java
deleted file mode 100644
index cdb3706a4..000000000
--- a/swing/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.sf.openrocket.gui.simulation;
-
-import java.awt.Component;
-import java.util.ArrayList;
-
-import javax.swing.JOptionPane;
-
-import net.sf.openrocket.logging.Warning;
-import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.dialogs.DetailDialog;
-import net.sf.openrocket.l10n.Translator;
-import net.sf.openrocket.startup.Application;
-
-public class SimulationWarningDialog {
-
- private static final Translator trans = Application.getTranslator();
-
- public static void showWarningDialog(Component parent, Simulation simulation) {
-
- if (simulation.getSimulatedWarnings() != null && simulation.getSimulatedWarnings().size() > 0) {
- ArrayList messages = new ArrayList();
- messages.add(trans.get("SimuRunDlg.msg.errorOccurred"));
- for (Warning m : simulation.getSimulatedWarnings()) {
- messages.add(m.toString());
- }
- DetailDialog.showDetailedMessageDialog(parent,
- messages.toArray(),
- null, simulation.getName(), JOptionPane.ERROR_MESSAGE);
- }
-
- }
-}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationWarningsPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationWarningsPanel.java
new file mode 100644
index 000000000..5084c6cb0
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationWarningsPanel.java
@@ -0,0 +1,112 @@
+package net.sf.openrocket.gui.simulation;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.BetterListCellRenderer;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.gui.util.UITheme;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.Warning;
+import net.sf.openrocket.logging.WarningSet;
+import net.sf.openrocket.startup.Application;
+
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.Icon;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.border.Border;
+import java.awt.Color;
+import java.util.List;
+
+public class SimulationWarningsPanel extends JPanel {
+ private static final Translator trans = Application.getTranslator();
+
+ private static Border border;
+ private static Color darkErrorColor;
+ private static Color warningColor;
+ private static Color informationColor;
+
+ static {
+ initColors();
+ }
+
+ public SimulationWarningsPanel(final Simulation simulation) {
+ super(new MigLayout("fill"));
+
+ WarningSet warnings = simulation.getSimulatedWarnings();
+ List criticalWarnings = warnings == null ? null : warnings.getCriticalWarnings();
+ List normalWarnings = warnings == null ? null : warnings.getNormalWarnings();
+ List informativeWarnings = warnings == null ? null : warnings.getInformativeWarnings();
+
+ // Critical warnings
+ JPanel criticalPanel = createWarningsPanel(criticalWarnings, Icons.WARNING_HIGH, trans.get("SimulationWarningsPanel.lbl.CriticalWarnings"), darkErrorColor);
+ this.add(criticalPanel, "spanx, grow, wrap 3lp");
+
+ // Normal warnings
+ JPanel normalPanel = createWarningsPanel(normalWarnings, Icons.WARNING_NORMAL, trans.get("SimulationWarningsPanel.lbl.NormalWarnings"), warningColor);
+ this.add(normalPanel, "spanx, grow, wrap 5lp");
+
+ // Informative warnings
+ //JPanel infoPanel = createWarningsPanel(informativeWarnings, Icons.WARNING_LOW, trans.get("SimulationWarningsPanel.lbl.InformativeWarnings"), informationColor);
+ //this.add(infoPanel, "spanx, grow, wrap 5lp");
+
+ JPanel filler = new JPanel();
+ this.add(filler, "grow, spanx, pushy");
+ }
+
+ private static void initColors() {
+ updateColors();
+ UITheme.Theme.addUIThemeChangeListener(SimulationWarningsPanel::updateColors);
+ }
+
+ private static void updateColors() {
+ border = GUIUtil.getUITheme().getBorder();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
+ warningColor = GUIUtil.getUITheme().getWarningColor();
+ informationColor = GUIUtil.getUITheme().getInformationColor();
+ }
+
+ private static JPanel createWarningsPanel(final List warnings, final Icon icon, final String titleText, Color textColor) {
+ JPanel panel = new JPanel(new MigLayout("fillx"));
+
+ // Title
+ float size = 1.1f;
+ int nrOfWarnings = warnings == null ? 0 : warnings.size();
+ StyledLabel title = new StyledLabel(nrOfWarnings + " " + titleText, size, StyledLabel.Style.BOLD);
+ title.setFontColor(textColor);
+ panel.add(title, "wrap, spanx");
+
+ if (nrOfWarnings == 0) {
+ return panel;
+ }
+
+ // Warning list
+ Warning[] w = warnings.toArray(new Warning[0]);
+ final JList warningList = new JList<>(w);
+ warningList.setSelectionModel(new NoSelectionModel()); // Disable selection
+ warningList.setCellRenderer(new BetterListCellRenderer(icon));
+ JScrollPane warningPane = new JScrollPane(warningList);
+ warningList.setBorder(border);
+ panel.add(warningPane, "wrap, spanx, growx");
+
+ return panel;
+ }
+
+ private static class NoSelectionModel extends DefaultListSelectionModel {
+
+ @Override
+ public void setAnchorSelectionIndex(final int anchorIndex) {}
+
+ @Override
+ public void setLeadAnchorNotificationEnabled(final boolean flag) {}
+
+ @Override
+ public void setLeadSelectionIndex(final int leadIndex) {}
+
+ @Override
+ public void setSelectionInterval(final int index0, final int index1) { }
+ }
+}
diff --git a/swing/src/net/sf/openrocket/gui/util/BetterListCellRenderer.java b/swing/src/net/sf/openrocket/gui/util/BetterListCellRenderer.java
index dfbb02be0..2f826a60d 100644
--- a/swing/src/net/sf/openrocket/gui/util/BetterListCellRenderer.java
+++ b/swing/src/net/sf/openrocket/gui/util/BetterListCellRenderer.java
@@ -2,6 +2,7 @@ package net.sf.openrocket.gui.util;
import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JList;
import java.awt.Color;
@@ -17,16 +18,41 @@ public class BetterListCellRenderer extends DefaultListCellRenderer {
private static Color rowBackgroundLighterColor;
private static Color textSelectionForegroundColor;
private static Color textColor;
+ private final Color textColorOverride;
+ private final Icon icon;
static {
initColors();
}
+ public BetterListCellRenderer(Icon icon, Color textColor) {
+ this.icon = icon;
+ this.textColorOverride = textColor;
+ }
+
+ public BetterListCellRenderer(Icon icon) {
+ this(icon, null);
+ }
+
+ public BetterListCellRenderer(Color textColor) {
+ this(null, textColor);
+ }
+
+ public BetterListCellRenderer() {
+ this.icon = null;
+ this.textColorOverride = null;
+ }
+
@Override
public Component getListCellRendererComponent(JList> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ if (icon != null) {
+ label.setIcon(icon);
+ label.setIconTextGap(10);
+ }
+
// Alternating row colors
if (!isSelected) {
if (index % 2 == 0) {
@@ -39,7 +65,7 @@ public class BetterListCellRenderer extends DefaultListCellRenderer {
if (isSelected) {
label.setForeground(textSelectionForegroundColor);
} else {
- label.setForeground(textColor);
+ label.setForeground(textColorOverride != null ? textColorOverride : textColor);
}
return label;
}
diff --git a/swing/src/net/sf/openrocket/gui/util/ColorConversion.java b/swing/src/net/sf/openrocket/gui/util/ColorConversion.java
index af1f17c5c..bf12959c1 100644
--- a/swing/src/net/sf/openrocket/gui/util/ColorConversion.java
+++ b/swing/src/net/sf/openrocket/gui/util/ColorConversion.java
@@ -2,6 +2,8 @@ package net.sf.openrocket.gui.util;
import net.sf.openrocket.util.ORColor;
+import java.awt.Color;
+
public class ColorConversion {
public static java.awt.Color toAwtColor( ORColor c ) {
@@ -17,4 +19,12 @@ public class ColorConversion {
}
return new ORColor( c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
}
+
+ public static String formatHTMLColor(Color c, String content) {
+ if (c == null) {
+ return null;
+ }
+ String hexColor = String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue());
+ return String.format("%s", hexColor, content);
+ }
}
diff --git a/swing/src/net/sf/openrocket/gui/util/Icons.java b/swing/src/net/sf/openrocket/gui/util/Icons.java
index 2d8a34ac4..afc53f907 100644
--- a/swing/src/net/sf/openrocket/gui/util/Icons.java
+++ b/swing/src/net/sf/openrocket/gui/util/Icons.java
@@ -29,13 +29,17 @@ public class Icons {
*/
public static final Map SIMULATION_STATUS_ICON_MAP;
static {
+ final String SIM_UPTODATE = "pix/icons/tick.png";
+ final String SIM_CANTRUN = "pix/icons/sim_cantrun.png";
+ final String SIM_OUTDATED = "pix/icons/refresh_sim.png";
+
HashMap map = new HashMap();
- map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon("pix/spheres/gray-16x16.png", "Not simulated"));
- map.put(Simulation.Status.CANT_RUN, loadImageIcon("pix/spheres/yellow-16x16.png", "Can't run, no motors assigned."));
- map.put(Simulation.Status.UPTODATE, loadImageIcon("pix/spheres/green-16x16.png", "Up to date"));
- map.put(Simulation.Status.LOADED, loadImageIcon("pix/spheres/blue-16x16.png", "Loaded from File"));
- map.put(Simulation.Status.OUTDATED, loadImageIcon("pix/spheres/red-16x16.png", "Out-of-date"));
- map.put(Simulation.Status.EXTERNAL, loadImageIcon("pix/spheres/blue-16x16.png", "Imported data"));
+ map.put(Simulation.Status.NOT_SIMULATED, loadImageIcon(SIM_OUTDATED, "Not simulated"));
+ map.put(Simulation.Status.CANT_RUN, loadImageIcon(SIM_CANTRUN, "Can't run, no motors assigned."));
+ map.put(Simulation.Status.UPTODATE, loadImageIcon(SIM_UPTODATE, "Up to date"));
+ map.put(Simulation.Status.LOADED, loadImageIcon(SIM_UPTODATE, "Loaded from File"));
+ map.put(Simulation.Status.OUTDATED, loadImageIcon(SIM_OUTDATED, "Out-of-date"));
+ map.put(Simulation.Status.EXTERNAL, loadImageIcon(SIM_UPTODATE, "Imported data"));
SIMULATION_STATUS_ICON_MAP = Collections.unmodifiableMap(map);
}
@@ -95,6 +99,10 @@ public class Icons {
public static final Icon NOT_FAVORITE = loadImageIcon("pix/icons/star_silver.png", "Not favorite");
public static final Icon FAVORITE = loadImageIcon("pix/icons/star_gold.png", "Favorite");
+ public static final Icon WARNING_LOW = loadImageIcon("pix/icons/warning_low.png", "Informative Warning");
+ public static final Icon WARNING_NORMAL = loadImageIcon("pix/icons/warning_normal.png", "Warning");
+ public static final Icon WARNING_HIGH = loadImageIcon("pix/icons/warning_high.png", "Critical Warning");
+
public static final Icon MASS_OVERRIDE_LIGHT = loadImageIcon("pix/icons/mass-override_light.png", "Mass Override");
public static final Icon MASS_OVERRIDE_DARK = loadImageIcon("pix/icons/mass-override_dark.png", "Mass Override");
public static final Icon MASS_OVERRIDE_SUBCOMPONENT_LIGHT = loadImageIcon("pix/icons/mass-override-subcomponent_light.png", "Mass Override Subcomponent");
diff --git a/swing/src/net/sf/openrocket/gui/util/UITheme.java b/swing/src/net/sf/openrocket/gui/util/UITheme.java
index 45e507102..a35dc066c 100644
--- a/swing/src/net/sf/openrocket/gui/util/UITheme.java
+++ b/swing/src/net/sf/openrocket/gui/util/UITheme.java
@@ -41,8 +41,10 @@ public class UITheme {
Color getDisabledTextColor();
Color getTextSelectionForegroundColor();
Color getTextSelectionBackgroundColor();
+ Color getInformationColor();
Color getWarningColor();
- Color getDarkWarningColor();
+ Color getErrorColor();
+ Color getDarkErrorColor();
Color getRowBackgroundLighterColor();
Color getRowBackgroundDarkerColor();
Color getFlightDataTextActiveColor();
@@ -221,13 +223,23 @@ public class UITheme {
return UIManager.getColor("Tree.selectionBackground");
}
+ @Override
+ public Color getInformationColor() {
+ return new Color(45, 45, 189);
+ }
+
@Override
public Color getWarningColor() {
+ return new Color(217, 152, 0);
+ }
+
+ @Override
+ public Color getErrorColor() {
return Color.RED;
}
@Override
- public Color getDarkWarningColor() {
+ public Color getDarkErrorColor() {
return new Color(200,0,0);
}
@@ -588,13 +600,23 @@ public class UITheme {
return new Color(75, 110, 175);
}
+ @Override
+ public Color getInformationColor() {
+ return new Color(208, 208, 255);
+ }
+
@Override
public Color getWarningColor() {
+ return new Color(255, 224, 166);
+ }
+
+ @Override
+ public Color getErrorColor() {
return new Color(246, 143, 143);
}
@Override
- public Color getDarkWarningColor() {
+ public Color getDarkErrorColor() {
return new Color(229, 103, 103);
}
@@ -952,13 +974,23 @@ public class UITheme {
return new Color(62, 108, 173);
}
+ @Override
+ public Color getInformationColor() {
+ return new Color(197, 197, 252);
+ }
+
@Override
public Color getWarningColor() {
+ return new Color(255, 233, 187);
+ }
+
+ @Override
+ public Color getErrorColor() {
return new Color(255, 173, 173);
}
@Override
- public Color getDarkWarningColor() {
+ public Color getDarkErrorColor() {
return new Color(255, 178, 178);
}
@@ -1328,14 +1360,24 @@ public class UITheme {
return getCurrentTheme().getTextSelectionBackgroundColor();
}
+ @Override
+ public Color getInformationColor() {
+ return getCurrentTheme().getInformationColor();
+ }
+
@Override
public Color getWarningColor() {
return getCurrentTheme().getWarningColor();
}
@Override
- public Color getDarkWarningColor() {
- return getCurrentTheme().getDarkWarningColor();
+ public Color getErrorColor() {
+ return getCurrentTheme().getErrorColor();
+ }
+
+ @Override
+ public Color getDarkErrorColor() {
+ return getCurrentTheme().getDarkErrorColor();
}
@Override
diff --git a/swing/src/net/sf/openrocket/simulation/extension/impl/JavaCodeConfigurator.java b/swing/src/net/sf/openrocket/simulation/extension/impl/JavaCodeConfigurator.java
index 6ce79068b..718afe916 100644
--- a/swing/src/net/sf/openrocket/simulation/extension/impl/JavaCodeConfigurator.java
+++ b/swing/src/net/sf/openrocket/simulation/extension/impl/JavaCodeConfigurator.java
@@ -26,7 +26,7 @@ public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfig
private static final Translator trans = Application.getTranslator();
- private static Color darkWarningColor;
+ private static Color darkErrorColor;
static {
initColors();
@@ -42,7 +42,7 @@ public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfig
}
private static void updateColors() {
- darkWarningColor = GUIUtil.getUITheme().getDarkWarningColor();
+ darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor();
}
@Override
@@ -53,7 +53,7 @@ public class JavaCodeConfigurator extends AbstractSwingSimulationExtensionConfig
classNameField = new JTextField(extension.getClassName());
panel.add(classNameField, "growx, wrap");
this.errorMsg = new StyledLabel();
- errorMsg.setFontColor(darkWarningColor);
+ errorMsg.setFontColor(darkErrorColor);
errorMsg.setVisible(false);
panel.add(errorMsg, "growx, wrap");